mirror of
https://github.com/AtlasMediaGroup/TotalFreedomMod.git
synced 2025-06-30 03:56:42 +00:00
[Bleeding] Revamped rank system yet again
Refractoring Bug fixes Mass format
This commit is contained in:
@ -0,0 +1,72 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import me.totalfreedom.totalfreedommod.httpd.HTTPDPageBuilder;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.HTTPSession;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Method;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
|
||||
public abstract class HTTPDModule
|
||||
{
|
||||
|
||||
protected final String uri;
|
||||
protected final Method method;
|
||||
protected final Map<String, String> headers;
|
||||
protected final Map<String, String> params;
|
||||
protected final Socket socket;
|
||||
protected final HTTPSession session;
|
||||
|
||||
public HTTPDModule(HTTPSession session)
|
||||
{
|
||||
this.uri = session.getUri();
|
||||
this.method = session.getMethod();
|
||||
this.headers = session.getHeaders();
|
||||
this.params = session.getParms();
|
||||
this.socket = session.getSocket();
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public String getBody()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getStyle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getScript()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Response getResponse()
|
||||
{
|
||||
return new HTTPDPageBuilder(getBody(), getTitle(), getStyle(), getScript()).getResponse();
|
||||
}
|
||||
|
||||
protected final Map<String, String> getFiles()
|
||||
{
|
||||
Map<String, String> files = new HashMap<String, String>();
|
||||
|
||||
try
|
||||
{
|
||||
session.parseBody(files);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
FLog.severe(ex);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.list;
|
||||
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.paragraph;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class Module_dump extends HTTPDModule
|
||||
{
|
||||
|
||||
private File echoFile = null;
|
||||
private final String body;
|
||||
|
||||
public Module_dump(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
|
||||
//Body needs to be computed before getResponse, so we know if a text response or a file echo is needed.
|
||||
this.body = body();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NanoHTTPD.Response getResponse()
|
||||
{
|
||||
String echo = params.get("echo");
|
||||
boolean doEcho = echo != null && ((echo = echo.toLowerCase().trim()).equalsIgnoreCase("true") || echo.equalsIgnoreCase("1"));
|
||||
|
||||
if (doEcho && this.echoFile != null && this.echoFile.exists())
|
||||
{
|
||||
return HTTPDaemon.serveFileBasic(this.echoFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.getResponse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody()
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
private String body()
|
||||
{
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
|
||||
String remoteAddress = socket.getInetAddress().getHostAddress();
|
||||
|
||||
String[] args = StringUtils.split(uri, "/");
|
||||
|
||||
Map<String, String> files = getFiles();
|
||||
|
||||
responseBody
|
||||
.append(paragraph("URI: " + uri))
|
||||
.append(paragraph("args (Length: " + args.length + "): " + StringUtils.join(args, ",")))
|
||||
.append(paragraph("Method: " + method.toString()))
|
||||
.append(paragraph("Remote Address: " + remoteAddress))
|
||||
.append(paragraph("Headers:"))
|
||||
.append(list(headers))
|
||||
.append(paragraph("Params:"))
|
||||
.append(list(params))
|
||||
.append(paragraph("Files:"))
|
||||
.append(list(files));
|
||||
|
||||
Iterator<Map.Entry<String, String>> it = files.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Map.Entry<String, String> entry = it.next();
|
||||
String formName = entry.getKey();
|
||||
String tempFileName = entry.getValue();
|
||||
String origFileName = params.get(formName);
|
||||
|
||||
File tempFile = new File(tempFileName);
|
||||
if (tempFile.exists())
|
||||
{
|
||||
this.echoFile = tempFile;
|
||||
|
||||
if (origFileName.contains("../"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
String targetFileName = "./public_html/uploads/" + origFileName;
|
||||
|
||||
File targetFile = new File(targetFileName);
|
||||
|
||||
try
|
||||
{
|
||||
FileUtils.copyFile(tempFile, targetFile);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
FLog.severe(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return responseBody.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle()
|
||||
{
|
||||
return "TotalFreedomMod :: Request Debug Dumper";
|
||||
}
|
||||
}
|
@ -0,0 +1,381 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/*
|
||||
* This class was adapted from https://github.com/NanoHttpd/nanohttpd/blob/master/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java
|
||||
*/
|
||||
public class Module_file extends HTTPDModule
|
||||
{
|
||||
|
||||
private final File rootDir = new File(ConfigEntry.HTTPD_PUBLIC_FOLDER.getString());
|
||||
public static final Map<String, String> MIME_TYPES = new HashMap<String, String>();
|
||||
|
||||
static
|
||||
{
|
||||
MIME_TYPES.put("css", "text/css");
|
||||
MIME_TYPES.put("htm", "text/html");
|
||||
MIME_TYPES.put("html", "text/html");
|
||||
MIME_TYPES.put("xml", "text/xml");
|
||||
MIME_TYPES.put("java", "text/x-java-source, text/java");
|
||||
MIME_TYPES.put("txt", "text/plain");
|
||||
MIME_TYPES.put("asc", "text/plain");
|
||||
MIME_TYPES.put("yml", "text/yaml");
|
||||
MIME_TYPES.put("gif", "image/gif");
|
||||
MIME_TYPES.put("jpg", "image/jpeg");
|
||||
MIME_TYPES.put("jpeg", "image/jpeg");
|
||||
MIME_TYPES.put("png", "image/png");
|
||||
MIME_TYPES.put("mp3", "audio/mpeg");
|
||||
MIME_TYPES.put("m3u", "audio/mpeg-url");
|
||||
MIME_TYPES.put("mp4", "video/mp4");
|
||||
MIME_TYPES.put("ogv", "video/ogg");
|
||||
MIME_TYPES.put("flv", "video/x-flv");
|
||||
MIME_TYPES.put("mov", "video/quicktime");
|
||||
MIME_TYPES.put("swf", "application/x-shockwave-flash");
|
||||
MIME_TYPES.put("js", "application/javascript");
|
||||
MIME_TYPES.put("pdf", "application/pdf");
|
||||
MIME_TYPES.put("doc", "application/msword");
|
||||
MIME_TYPES.put("ogg", "application/x-ogg");
|
||||
MIME_TYPES.put("zip", "application/octet-stream");
|
||||
MIME_TYPES.put("exe", "application/octet-stream");
|
||||
MIME_TYPES.put("class", "application/octet-stream");
|
||||
}
|
||||
|
||||
public Module_file(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
private File getRootDir()
|
||||
{
|
||||
return rootDir;
|
||||
}
|
||||
|
||||
private String encodeUri(String uri)
|
||||
{
|
||||
String newUri = "";
|
||||
StringTokenizer st = new StringTokenizer(uri, "/ ", true);
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
String tok = st.nextToken();
|
||||
if (tok.equals("/"))
|
||||
{
|
||||
newUri += "/";
|
||||
}
|
||||
else if (tok.equals(" "))
|
||||
{
|
||||
newUri += "%20";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
newUri += URLEncoder.encode(tok, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return newUri;
|
||||
}
|
||||
|
||||
public Response serveFile(String uri, Map<String, String> params, File homeDir)
|
||||
{
|
||||
Response res = null;
|
||||
|
||||
// Make sure we won't die of an exception later
|
||||
if (!homeDir.isDirectory())
|
||||
{
|
||||
res = new Response(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "INTERNAL ERRROR: serveFile(): given homeDir is not a directory.");
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
// Remove URL arguments
|
||||
uri = uri.trim().replace(File.separatorChar, '/');
|
||||
if (uri.indexOf('?') >= 0)
|
||||
{
|
||||
uri = uri.substring(0, uri.indexOf('?'));
|
||||
}
|
||||
|
||||
// Prohibit getting out of current directory
|
||||
if (uri.startsWith("src/main") || uri.endsWith("src/main") || uri.contains("../"))
|
||||
{
|
||||
res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: Won't serve ../ for security reasons.");
|
||||
}
|
||||
}
|
||||
|
||||
File f = new File(homeDir, uri);
|
||||
if (res == null && !f.exists())
|
||||
{
|
||||
res = new Response(Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Error 404, file not found.");
|
||||
}
|
||||
|
||||
// List the directory, if necessary
|
||||
if (res == null && f.isDirectory())
|
||||
{
|
||||
// Browsers get confused without '/' after the
|
||||
// directory, send a redirect.
|
||||
if (!uri.endsWith("/"))
|
||||
{
|
||||
uri += "/";
|
||||
res = new Response(Response.Status.REDIRECT, NanoHTTPD.MIME_HTML, "<html><body>Redirected: <a href=\"" + uri + "\">" + uri
|
||||
+ "</a></body></html>");
|
||||
res.addHeader("Location", uri);
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
// First try index.html and index.htm
|
||||
if (new File(f, "index.html").exists())
|
||||
{
|
||||
f = new File(homeDir, uri + "/index.html");
|
||||
}
|
||||
else if (new File(f, "index.htm").exists())
|
||||
{
|
||||
f = new File(homeDir, uri + "/index.htm");
|
||||
}
|
||||
else if (f.canRead())
|
||||
{
|
||||
// No index file, list the directory if it is readable
|
||||
res = new Response(listDirectory(uri, f));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: No directory listing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (res == null)
|
||||
{
|
||||
// Get MIME type from file name extension, if possible
|
||||
String mime = null;
|
||||
int dot = f.getCanonicalPath().lastIndexOf('.');
|
||||
if (dot >= 0)
|
||||
{
|
||||
mime = MIME_TYPES.get(f.getCanonicalPath().substring(dot + 1).toLowerCase());
|
||||
}
|
||||
if (mime == null)
|
||||
{
|
||||
mime = HTTPDaemon.MIME_DEFAULT_BINARY;
|
||||
}
|
||||
|
||||
// Calculate etag
|
||||
String etag = Integer.toHexString((f.getAbsolutePath() + f.lastModified() + "" + f.length()).hashCode());
|
||||
|
||||
final long fileLen = f.length();
|
||||
|
||||
long startFrom = 0;
|
||||
long endAt = -1;
|
||||
final String range = params.get("range");
|
||||
if (range != null)
|
||||
{
|
||||
final String[] rangeParams = StringUtils.split(range, "=");
|
||||
if (rangeParams.length >= 2)
|
||||
{
|
||||
if ("bytes".equalsIgnoreCase(rangeParams[0]))
|
||||
{
|
||||
try
|
||||
{
|
||||
int minus = rangeParams[1].indexOf('-');
|
||||
if (minus > 0)
|
||||
{
|
||||
startFrom = Long.parseLong(rangeParams[1].substring(0, minus));
|
||||
endAt = Long.parseLong(rangeParams[1].substring(minus + 1));
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
else if ("tail".equalsIgnoreCase(rangeParams[0]))
|
||||
{
|
||||
try
|
||||
{
|
||||
final long tailLen = Long.parseLong(rangeParams[1]);
|
||||
if (tailLen < fileLen)
|
||||
{
|
||||
startFrom = fileLen - tailLen - 2;
|
||||
if (startFrom < 0)
|
||||
{
|
||||
startFrom = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change return code and add Content-Range header when skipping is requested
|
||||
if (range != null && startFrom >= 0)
|
||||
{
|
||||
if (startFrom >= fileLen)
|
||||
{
|
||||
res = new Response(Response.Status.RANGE_NOT_SATISFIABLE, NanoHTTPD.MIME_PLAINTEXT, "");
|
||||
res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
|
||||
res.addHeader("ETag", etag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endAt < 0)
|
||||
{
|
||||
endAt = fileLen - 1;
|
||||
}
|
||||
long newLen = endAt - startFrom + 1;
|
||||
if (newLen < 0)
|
||||
{
|
||||
newLen = 0;
|
||||
}
|
||||
|
||||
final long dataLen = newLen;
|
||||
FileInputStream fis = new FileInputStream(f)
|
||||
{
|
||||
@Override
|
||||
public int available() throws IOException
|
||||
{
|
||||
return (int) dataLen;
|
||||
}
|
||||
};
|
||||
fis.skip(startFrom);
|
||||
|
||||
res = new Response(Response.Status.PARTIAL_CONTENT, mime, fis);
|
||||
res.addHeader("Content-Length", "" + dataLen);
|
||||
res.addHeader("Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen);
|
||||
res.addHeader("ETag", etag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = new Response(Response.Status.OK, mime, new FileInputStream(f));
|
||||
res.addHeader("Content-Length", "" + fileLen);
|
||||
res.addHeader("ETag", etag);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: Reading file failed.");
|
||||
}
|
||||
|
||||
res.addHeader("Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requestes
|
||||
return res;
|
||||
}
|
||||
|
||||
private String listDirectory(String uri, File f)
|
||||
{
|
||||
String heading = "Directory " + uri;
|
||||
String msg = "<html><head><title>" + heading + "</title><style><!--\n"
|
||||
+ "span.dirname { font-weight: bold; }\n"
|
||||
+ "span.filesize { font-size: 75%; }\n"
|
||||
+ "// -->\n"
|
||||
+ "</style>"
|
||||
+ "</head><body><h1>" + heading + "</h1>";
|
||||
|
||||
String up = null;
|
||||
if (uri.length() > 1)
|
||||
{
|
||||
String u = uri.substring(0, uri.length() - 1);
|
||||
int slash = u.lastIndexOf('/');
|
||||
if (slash >= 0 && slash < u.length())
|
||||
{
|
||||
up = uri.substring(0, slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> files = Arrays.asList(f.list(new FilenameFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
return new File(dir, name).isFile();
|
||||
}
|
||||
}));
|
||||
Collections.sort(files);
|
||||
List<String> directories = Arrays.asList(f.list(new FilenameFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
return new File(dir, name).isDirectory();
|
||||
}
|
||||
}));
|
||||
Collections.sort(directories);
|
||||
if (up != null || directories.size() + files.size() > 0)
|
||||
{
|
||||
msg += "<ul>";
|
||||
if (up != null || directories.size() > 0)
|
||||
{
|
||||
msg += "<section class=\"directories\">";
|
||||
if (up != null)
|
||||
{
|
||||
msg += "<li><a rel=\"directory\" href=\"" + up + "\"><span class=\"dirname\">..</span></a></b></li>";
|
||||
}
|
||||
for (int i = 0; i < directories.size(); i++)
|
||||
{
|
||||
String dir = directories.get(i) + "/";
|
||||
msg += "<li><a rel=\"directory\" href=\"" + encodeUri(uri + dir) + "\"><span class=\"dirname\">" + dir + "</span></a></b></li>";
|
||||
}
|
||||
msg += "</section>";
|
||||
}
|
||||
if (files.size() > 0)
|
||||
{
|
||||
msg += "<section class=\"files\">";
|
||||
for (int i = 0; i < files.size(); i++)
|
||||
{
|
||||
String file = files.get(i);
|
||||
|
||||
msg += "<li><a href=\"" + encodeUri(uri + file) + "\"><span class=\"filename\">" + file + "</span></a>";
|
||||
File curFile = new File(f, file);
|
||||
long len = curFile.length();
|
||||
msg += " <span class=\"filesize\">(";
|
||||
if (len < 1024)
|
||||
{
|
||||
msg += len + " bytes";
|
||||
}
|
||||
else if (len < 1024 * 1024)
|
||||
{
|
||||
msg += len / 1024 + "." + (len % 1024 / 10 % 100) + " KB";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg += len / (1024 * 1024) + "." + len % (1024 * 1024) / 10 % 100 + " MB";
|
||||
}
|
||||
msg += ")</span></li>";
|
||||
}
|
||||
msg += "</section>";
|
||||
}
|
||||
msg += "</ul>";
|
||||
}
|
||||
msg += "</body></html>";
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getResponse()
|
||||
{
|
||||
return serveFile(uri, params, getRootDir());
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.commands.FreedomCommand;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.heading;
|
||||
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.paragraph;
|
||||
import me.totalfreedom.totalfreedommod.rank.PlayerRank;
|
||||
import me.totalfreedom.totalfreedommod.rank.Rank;
|
||||
import net.pravian.aero.command.CommandReflection;
|
||||
import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.PluginIdentifiableCommand;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
|
||||
public class Module_help extends HTTPDModule
|
||||
{
|
||||
|
||||
public Module_help(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody()
|
||||
{
|
||||
final CommandMap map = CommandReflection.getCommandMap();
|
||||
if (map == null || !(map instanceof SimpleCommandMap))
|
||||
{
|
||||
return paragraph("Error loading commands.");
|
||||
}
|
||||
|
||||
final StringBuilder responseBody = new StringBuilder()
|
||||
.append(heading("Command Help", 1))
|
||||
.append(paragraph(
|
||||
"This page is an automatically generated listing of all plugin commands that are currently live on the server. "
|
||||
+ "Please note that it does not include vanilla server commands."));
|
||||
|
||||
final Collection<Command> knownCommands = ((SimpleCommandMap) map).getCommands();
|
||||
final Map<String, List<Command>> commandsByPlugin = new HashMap<String, List<Command>>();
|
||||
|
||||
for (Command command : knownCommands)
|
||||
{
|
||||
String pluginName = "Bukkit";
|
||||
if (command instanceof PluginIdentifiableCommand)
|
||||
{
|
||||
pluginName = ((PluginIdentifiableCommand) command).getPlugin().getName();
|
||||
}
|
||||
|
||||
List<Command> pluginCommands = commandsByPlugin.get(pluginName);
|
||||
if (pluginCommands == null)
|
||||
{
|
||||
pluginCommands = Lists.newArrayList();
|
||||
commandsByPlugin.put(pluginName, pluginCommands);
|
||||
}
|
||||
|
||||
pluginCommands.add(command);
|
||||
}
|
||||
|
||||
final Iterator<Map.Entry<String, List<Command>>> it = commandsByPlugin.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
final Map.Entry<String, List<Command>> entry = it.next();
|
||||
final String pluginName = entry.getKey();
|
||||
final List<Command> commands = entry.getValue();
|
||||
|
||||
Collections.sort(commands, new CommandComparator());
|
||||
|
||||
responseBody.append(heading(pluginName, 2)).append("<ul>\r\n");
|
||||
|
||||
Rank lastTfmCommandLevel = null;
|
||||
for (Command command : commands)
|
||||
{
|
||||
if (!TotalFreedomMod.pluginName.equals(pluginName))
|
||||
{
|
||||
responseBody.append(buildDescription(command));
|
||||
continue;
|
||||
}
|
||||
|
||||
Rank tfmCommandLevel = FreedomCommand.getCommand(command).getPerms().level();
|
||||
if (lastTfmCommandLevel == null || lastTfmCommandLevel != tfmCommandLevel)
|
||||
{
|
||||
responseBody.append("</ul>\r\n").append(heading(tfmCommandLevel.getName(), 3)).append("<ul>\r\n");
|
||||
}
|
||||
lastTfmCommandLevel = tfmCommandLevel;
|
||||
responseBody.append(buildDescription(command));
|
||||
}
|
||||
|
||||
responseBody.append("</ul>\r\n");
|
||||
}
|
||||
|
||||
return responseBody.toString();
|
||||
}
|
||||
|
||||
private static String buildDescription(Command command)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(
|
||||
"<li><span class=\"commandName\">{$CMD_NAME}</span> - Usage: <span class=\"commandUsage\">{$CMD_USAGE}</span>"
|
||||
.replace("{$CMD_NAME}", escapeHtml4(command.getName().trim()))
|
||||
.replace("{$CMD_USAGE}", escapeHtml4(command.getUsage().trim())));
|
||||
|
||||
if (!command.getAliases().isEmpty())
|
||||
{
|
||||
sb.append(
|
||||
" - Aliases: <span class=\"commandAliases\">{$CMD_ALIASES}</span>"
|
||||
.replace("{$CMD_ALIASES}", escapeHtml4(StringUtils.join(command.getAliases(), ", "))));
|
||||
}
|
||||
|
||||
sb.append(
|
||||
"<br><span class=\"commandDescription\">{$CMD_DESC}</span></li>\r\n"
|
||||
.replace("{$CMD_DESC}", escapeHtml4(command.getDescription().trim())));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle()
|
||||
{
|
||||
return "TotalFreedomMod :: Command Help";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStyle()
|
||||
{
|
||||
return ".commandName{font-weight:bold;}.commandDescription{padding-left:15px;}li{margin:.15em;padding:.15em;}";
|
||||
}
|
||||
|
||||
public static class CommandComparator implements Comparator<Command>
|
||||
{
|
||||
|
||||
@Override
|
||||
public int compare(Command a, Command b)
|
||||
{
|
||||
FreedomCommand ca = FreedomCommand.getCommand(a);
|
||||
FreedomCommand cb = FreedomCommand.getCommand(b);
|
||||
|
||||
if (ca == null
|
||||
|| cb == null
|
||||
|| ca.getPerms() == null
|
||||
|| cb.getPerms() == null)
|
||||
{
|
||||
return a.getName().compareTo(b.getName());
|
||||
}
|
||||
|
||||
return ca.getPerms().level().getName().compareTo(cb.getPerms().level().getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.util.Collection;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Module_list extends HTTPDModule
|
||||
{
|
||||
|
||||
public Module_list(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody()
|
||||
{
|
||||
final StringBuilder body = new StringBuilder();
|
||||
|
||||
final Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
|
||||
|
||||
body.append("<p>There are ").append(onlinePlayers.size()).append("/").append(Bukkit.getMaxPlayers()).append(" players online:</p>\r\n");
|
||||
|
||||
body.append("<ul>\r\n");
|
||||
|
||||
for (Player player : onlinePlayers)
|
||||
{
|
||||
String tag = TotalFreedomMod.plugin.rm.getDisplayRank(player).getTag();
|
||||
body.append("<li>").append(tag).append(player.getName()).append("</li>\r\n");
|
||||
}
|
||||
|
||||
body.append("</ul>\r\n");
|
||||
|
||||
return body.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle()
|
||||
{
|
||||
return "Total Freedom - Online Users";
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.io.File;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
|
||||
public class Module_logs extends Module_file
|
||||
{
|
||||
|
||||
public Module_logs(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NanoHTTPD.Response getResponse()
|
||||
{
|
||||
if (ConfigEntry.LOGS_SECRET.getString().equals(params.get("password")))
|
||||
{
|
||||
return serveFile("latest.log", params, new File("./logs"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "Incorrect password.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import java.io.File;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
|
||||
public class Module_permbans extends HTTPDModule
|
||||
{
|
||||
|
||||
public Module_permbans(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NanoHTTPD.Response getResponse()
|
||||
{
|
||||
File permbanFile = new File(TotalFreedomMod.plugin.getDataFolder(), TotalFreedomMod.PERMBAN_FILENAME);
|
||||
if (permbanFile.exists())
|
||||
{
|
||||
return HTTPDaemon.serveFileBasic(new File(TotalFreedomMod.plugin.getDataFolder(), TotalFreedomMod.PERMBAN_FILENAME));
|
||||
}
|
||||
else
|
||||
{
|
||||
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT,
|
||||
"Error 404: Not Found - The requested resource was not found on this server.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package me.totalfreedom.totalfreedommod.httpd.module;
|
||||
|
||||
import me.totalfreedom.totalfreedommod.admin.Admin;
|
||||
import me.totalfreedom.totalfreedommod.util.FUtil;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class Module_players extends HTTPDModule
|
||||
{
|
||||
|
||||
public Module_players(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public NanoHTTPD.Response getResponse()
|
||||
{
|
||||
final JSONObject responseObject = new JSONObject();
|
||||
|
||||
final JSONArray players = new JSONArray();
|
||||
final JSONArray superadmins = new JSONArray();
|
||||
final JSONArray telnetadmins = new JSONArray();
|
||||
final JSONArray senioradmins = new JSONArray();
|
||||
final JSONArray developers = new JSONArray();
|
||||
|
||||
// All online players
|
||||
for (Player player : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
players.add(player.getName());
|
||||
}
|
||||
|
||||
// Admins
|
||||
for (Admin admin : TotalFreedomMod.plugin.al.getAllAdmins().values())
|
||||
{
|
||||
final String username = admin.getName();
|
||||
|
||||
switch (admin.getRank())
|
||||
{
|
||||
case SUPER_ADMIN:
|
||||
superadmins.add(username);
|
||||
break;
|
||||
case TELNET_ADMIN:
|
||||
telnetadmins.add(username);
|
||||
break;
|
||||
case SENIOR_ADMIN:
|
||||
senioradmins.add(senioradmins);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Developers
|
||||
developers.addAll(FUtil.DEVELOPERS);
|
||||
|
||||
responseObject.put("players", players);
|
||||
responseObject.put("superadmins", superadmins);
|
||||
responseObject.put("telnetadmins", telnetadmins);
|
||||
responseObject.put("senioradmins", senioradmins);
|
||||
responseObject.put("developers", developers);
|
||||
|
||||
final NanoHTTPD.Response response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, NanoHTTPD.MIME_JSON, responseObject.toString());
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
return response;
|
||||
}
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
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.admin.Admin;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Method;
|
||||
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
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 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(NanoHTTPD.HTTPSession session)
|
||||
{
|
||||
super(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<String>();
|
||||
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 = TotalFreedomMod.plugin.al.getEntryByIp(remoteAddress);
|
||||
return entry != null && entry.isActivated();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user