Merge branch '3.6.0' into master

This commit is contained in:
Fuzzlemann 2017-07-29 21:44:53 +02:00 committed by GitHub
commit d1be610e96
23 changed files with 448 additions and 284 deletions

View File

@ -42,11 +42,14 @@ import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.Check;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.metrics.BStats;
import org.bukkit.Bukkit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.LoggerConfig;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executors;
@ -186,7 +189,11 @@ public class Plan extends BukkitPlugin<Plan> {
Log.error("WebServer was not Initialized.");
}
// Prevent passwords showing up on console.
Bukkit.getLogger().setFilter(new RegisterCommandFilter());
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Collection<LoggerConfig> lc = ctx.getConfiguration().getLoggers().values();
for (LoggerConfig c : lc) {
c.addFilter(new RegisterCommandFilter());
}
} else if (!hasDataViewCapability) {
Log.infoColor(Phrase.ERROR_NO_DATA_VIEW.toString());
}
@ -390,7 +397,7 @@ public class Plan extends BukkitPlugin<Plan> {
}
try (InputStream inputStream = localeURL.openStream();
OutputStream outputStream = new FileOutputStream(localeFile)) {
OutputStream outputStream = new FileOutputStream(localeFile)) {
int read;
byte[] bytes = new byte[1024];
@ -421,9 +428,8 @@ public class Plan extends BukkitPlugin<Plan> {
/**
* Stops initializing the locale
*
* @implNote Removes clutter in the method
*
* @param usingLocale The locale that's used
* @implNote Removes clutter in the method
*/
private void stopInitLocale(String usingLocale) {
Benchmark.stop("Enable: Initializing locale");

View File

@ -53,7 +53,7 @@ public enum Settings {
WEBSERVER_CERTIFICATE_KEYPASS("Settings.WebServer.Security.Certificate.KeyPass"),
WEBSERVER_CERTIFICATE_STOREPASS("Settings.WebServer.Security.Certificate.KeyPass"),
WEBSERVER_CERTIFICATE_ALIAS("Settings.WebServer.Security.Certificate.Alias"),
LINK_PROTOCOL("Settings.WebServer.LinkProtocol"),
LINK_PROTOCOL("Settings.WebServer.ExternalWebServerLinkProtocol"),
//
SERVER_NAME("Customization.ServerName"),
//

View File

@ -68,23 +68,25 @@ public class AnalyzeCommand extends SubCommand {
}
sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + "");
plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") {
@Override
public void run() {
try {
if (CommandUtils.isPlayer(sender)) {
boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName());
if (!senderHasWebUser) {
sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register <password>");
if (plugin.getUiServer().isAuthRequired()) {
plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") {
@Override
public void run() {
try {
if (CommandUtils.isPlayer(sender)) {
boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName());
if (!senderHasWebUser) {
sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register <password>");
}
}
} catch (Exception e) {
Log.toLog(this.getClass().getName() + getName(), e);
} finally {
this.cancel();
}
} catch (Exception e) {
Log.toLog(this.getClass().getName() + getName(), e);
} finally {
this.cancel();
}
}
}).runTaskAsynchronously();
}).runTaskAsynchronously();
}
updateCache();
runMessageSenderTask(sender);
return true;

View File

@ -90,7 +90,7 @@ public class InspectCommand extends SubCommand {
return;
}
sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + "");
if (CommandUtils.isPlayer(sender)) {
if (CommandUtils.isPlayer(sender) && plugin.getUiServer().isAuthRequired()) {
boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName());
if (!senderHasWebUser) {
sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register <password>");

View File

@ -1,7 +1,11 @@
package main.java.com.djrapitops.plan.command.commands;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.message.Message;
/**
* Filters out WebUser registration command logs.
@ -11,12 +15,126 @@ import java.util.logging.LogRecord;
*/
public class RegisterCommandFilter implements Filter {
@Override
public boolean isLoggable(LogRecord record) {
String message = record.getMessage();
private boolean start = true;
private Result filter(String message) {
boolean block = message.contains("command: /plan register")
|| message.contains("command: /plan web register")
|| message.contains("command: /plan webuser register");
return !block;
if (block) {
return Result.DENY;
}
return null;
}
@Override
public Result filter(LogEvent event) {
String message = event.getMessage().toString().toLowerCase();
return filter(message);
}
@Override
public Result filter(Logger arg0, Level arg1, Marker arg2, String arg3, Object... arg4) {
return filter(arg3);
}
@Override
public Result filter(Logger arg0, Level arg1, Marker arg2, Object arg3, Throwable arg4) {
return null;
}
@Override
public Result filter(Logger arg0, Level arg1, Marker arg2, Message arg3, Throwable arg4) {
return filter(arg3.toString());
}
@Override
public Result getOnMatch() {
return null;
}
@Override
public Result getOnMismatch() {
return null;
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4, Object o5) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8) {
return filter(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object o, Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8, Object o9) {
return filter(s);
}
@Override
public State getState() {
return null;
}
@Override
public void initialize() {
}
@Override
public void start() {
start = true;
}
@Override
public void stop() {
start = false;
}
@Override
public boolean isStarted() {
return start;
}
@Override
public boolean isStopped() {
return !start;
}
}

View File

@ -805,7 +805,6 @@ public class UserData {
result = 31 * result + deaths;
result = 31 * result + name.hashCode();
result = 31 * result + (isOnline ? 1 : 0);
result = 31 * result + currentSession.hashCode();
return result;
}

View File

@ -42,7 +42,7 @@ import java.util.*;
public class DataCacheHandler extends SessionCache {
// Cache
private final HashMap<UUID, UserData> dataCache;
private final Map<UUID, UserData> dataCache;
// Plan
private final Plan plugin;

View File

@ -199,15 +199,17 @@ public class NicknamesTable extends Table {
lastNicks.put(id, nickname);
}
}
//TODO figure out what the heck that method does @Rsl1122
for (Map.Entry<Integer, String> entrySet : lastNicks.entrySet()) {
Integer id = entrySet.getKey();
String lastNick = entrySet.getValue();
for (Map.Entry<Integer, String> entry : lastNicks.entrySet()) {
Integer id = entry.getKey();
String lastNick = entry.getValue();
List<String> list = nicks.get(id);
list.remove(lastNick); //NOTE: Remove here?
list.add(lastNick); //NOTE: And add here again?
// Moves the last known nickname to the end of the List.
// This is due to the way nicknames are added to UserData,
// Nicknames are stored as a Set and last Nickname is a separate String.
list.remove(lastNick);
list.add(lastNick);
}
return nicks;

View File

@ -1,6 +1,5 @@
package main.java.com.djrapitops.plan.ui.html.graphs;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.data.SessionData;
import main.java.com.djrapitops.plan.data.TPS;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
@ -41,8 +40,6 @@ public class PlayerActivityGraphCreator {
.map(session -> new Point[]{new Point(session.getSessionStart(), 1), new Point(session.getSessionEnd(), 0)})
.flatMap(Arrays::stream)
.collect(Collectors.toList());
Log.debug(points.stream().map(Point::getY).collect(Collectors.toList()).toString());
return ScatterGraphCreator.scatterGraph(points, true, false);
}

View File

@ -1,66 +0,0 @@
package main.java.com.djrapitops.plan.ui.webserver;
import com.sun.net.httpserver.BasicAuthenticator;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
import java.sql.SQLException;
public class Authenticator extends BasicAuthenticator {
private final Plan plugin;
public Authenticator(Plan plugin, String realm) {
super(realm);
this.plugin = plugin;
}
@Override
public boolean checkCredentials(String user, String pwd) {
try {
return isAuthorized(user, pwd, this.realm);
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
return false;
}
}
private boolean isAuthorized(String user, String passwordRaw, String target) throws PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException, SQLException {
SecurityTable securityTable = plugin.getDB().getSecurityTable();
if (!securityTable.userExists(user)) {
return false;
}
WebUser securityInfo = securityTable.getSecurityInfo(user);
boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, securityInfo.getSaltedPassHash());
if (!correctPass) {
return false;
}
int permLevel = securityInfo.getPermLevel(); // Lower number has higher clearance.
int required = getRequiredPermLevel(target, securityInfo.getName());
return permLevel <= required;
}
private int getRequiredPermLevel(String target, String user) {
String[] t = target.split("/");
if (t.length < 3) {
return 0;
}
final String wantedUser = t[2].toLowerCase().trim();
final String theUser = user.trim().toLowerCase();
if (t[1].equals("players")) {
return 1;
}
if (t[1].equals("player")) {
if (wantedUser.equals(theUser)) {
return 2;
} else {
return 1;
}
}
return 0;
}
}

View File

@ -1,25 +1,30 @@
package main.java.com.djrapitops.plan.ui.webserver;
import com.djrapitops.plugin.utilities.Verify;
import com.sun.net.httpserver.*;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.response.*;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import org.bukkit.ChatColor;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@ -35,7 +40,8 @@ public class WebServer {
private boolean enabled = false;
private HttpServer server;
private final int port;
private boolean shutdown;
private boolean usingHttps;
/**
* Class Constructor.
@ -47,7 +53,6 @@ public class WebServer {
public WebServer(Plan plugin) {
this.plugin = plugin;
this.port = Settings.WEBSERVER_PORT.getNumber();
shutdown = false;
dataReqHandler = new DataRequestHandler(plugin);
}
@ -62,83 +67,51 @@ public class WebServer {
Log.info(Phrase.WEBSERVER_INIT.toString());
try {
String keyStorePath = Settings.WEBSERVER_CERTIFICATE_PATH.toString();
if (!keyStorePath.contains(":")) {
keyStorePath = plugin.getDataFolder() + keyStorePath;
}
char[] storepass = Settings.WEBSERVER_CERTIFICATE_STOREPASS.toString().toCharArray();
char[] keypass = Settings.WEBSERVER_CERTIFICATE_KEYPASS.toString().toCharArray();
String alias = Settings.WEBSERVER_CERTIFICATE_ALIAS.toString();
usingHttps = startHttpsServer();
boolean startSuccessful = false;
try (FileInputStream fIn = new FileInputStream(keyStorePath)) {
KeyStore keystore = KeyStore.getInstance("JKS");
Log.debug(usingHttps ? "Https Start Successful." : "Https Start Failed.");
keystore.load(fIn, storepass);
Certificate cert = keystore.getCertificate(alias);
Log.info("Found Certificate: " + cert.getType());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keystore, keypass);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keystore);
server = HttpsServer.create(new InetSocketAddress(port), 10);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagerFactory.getKeyManagers(), null/*trustManagerFactory.getTrustManagers()*/, null);
((HttpsServer) server).setHttpsConfigurator(new HttpsConfigurator(sslContext) {
@Override
public void configure(HttpsParameters params) {
SSLEngine engine = sslContext.createSSLEngine();
params.setNeedClientAuth(false);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
SSLParameters defaultSSLParameters = sslContext.getDefaultSSLParameters();
params.setSSLParameters(defaultSSLParameters);
}
});
startSuccessful = true;
} catch (KeyManagementException | NoSuchAlgorithmException e) {
Log.error("WebServer: SSL Context Initialization Failed.");
Log.toLog(this.getClass().getName(), e);
} catch (FileNotFoundException e) {
Log.error("!--------!---------!---------!");
Log.error("WebServer: SSL Certificate KeyStore File not Found: " + keyStorePath);
Log.error("!--------!---------!---------!");
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) {
Log.error("WebServer: SSL Certificate loading Failed.");
Log.toLog(this.getClass().getName(), e);
if (!usingHttps) {
server = HttpServer.create(new InetSocketAddress(port), 10);
}
Log.debug("Start Successful: " + startSuccessful);
if (!startSuccessful) {
return; // TODO Http Server
}
Log.debug("Create server context");
HttpContext context = server.createContext("/", new HttpHandler() {
server.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange xghng) throws IOException {
HttpsExchange exchange = (HttpsExchange) xghng;
public void handle(HttpExchange exchange) throws IOException {
OutputStream os = null;
try {
URI uri = exchange.getRequestURI();
String target = uri.toString();
Response response = getResponse(target);
WebUser user = null;
if (usingHttps) {
user = getUser(exchange.getRequestHeaders());
// Prompt authorization
if (user == null) {
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\";");
}
}
Response response = getResponse(target, user);
String content = response.getContent();
exchange.sendResponseHeaders(response.getCode(), content.length());
OutputStream os = exchange.getResponseBody();
os.write(content.getBytes());
os.close();
try (BufferedOutputStream out = new BufferedOutputStream(exchange.getResponseBody())) {
try (ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes())) {
byte[] buffer = new byte[2048];
int count;
while ((count = bis.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
}
}
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
} finally {
MiscUtils.close(os);
exchange.close();
}
}
});
@ -150,6 +123,7 @@ public class WebServer {
server.setExecutor(new ThreadPoolExecutor(4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)));
server.start();
enabled = true;
Log.info(Phrase.WEBSERVER_RUNNING.parse(String.valueOf(server.getAddress().getPort())));
@ -159,68 +133,192 @@ public class WebServer {
}
}
// if (!request.hasAuthorization()) {
// return new PromptAuthorizationResponse(output);
// }
// try {
// if (!isAuthorized(request)) {
// ForbiddenResponse response403 = new ForbiddenResponse(output);
// String content = "<h1>403 Forbidden - Access Denied</h1>"
// + "<p>Unauthorized User.<br>"
// + "Make sure your user has the correct access level.<br>"
// + "You can use /plan web check <username> to check the permission level.</p>";
// response403.setContent(content);
// return response403;
// }
private WebUser getUser(Headers requestHeaders) {
try {
List<String> authorization = requestHeaders.get("Authorization");
if (Verify.isEmpty(authorization)) {
return null;
}
String auth = authorization.get(0);
if (auth.contains("Basic ")) {
auth = auth.split(" ")[1];
} else {
throw new IllegalArgumentException("Wrong format of Auth");
}
Base64.Decoder decoder = Base64.getDecoder();
byte[] decoded = decoder.decode(auth);
String[] userInfo = new String(decoded).split(":");
if (userInfo.length != 2) {
throw new IllegalArgumentException("User and Password not specified");
}
String user = userInfo[0];
String passwordRaw = userInfo[1];
private Response getResponse(String target) {
SecurityTable securityTable = plugin.getDB().getSecurityTable();
if (!securityTable.userExists(user)) {
throw new IllegalArgumentException("User Doesn't exist");
}
WebUser webUser = securityTable.getSecurityInfo(user);
boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, webUser.getSaltedPassHash());
if (!correctPass) {
throw new IllegalArgumentException("User and Password do not match");
}
return webUser;
} catch (IllegalArgumentException e) {
Log.debug("WebServer: " + e.getMessage());
return null;
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
return null;
}
}
private boolean startHttpsServer() throws IOException {
String keyStorePath = Settings.WEBSERVER_CERTIFICATE_PATH.toString();
if (!keyStorePath.contains(":")) {
keyStorePath = plugin.getDataFolder() + keyStorePath;
}
char[] storepass = Settings.WEBSERVER_CERTIFICATE_STOREPASS.toString().toCharArray();
char[] keypass = Settings.WEBSERVER_CERTIFICATE_KEYPASS.toString().toCharArray();
String alias = Settings.WEBSERVER_CERTIFICATE_ALIAS.toString();
boolean startSuccessful = false;
try (FileInputStream fIn = new FileInputStream(keyStorePath)) {
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(fIn, storepass);
Certificate cert = keystore.getCertificate(alias);
Log.info("Found Certificate: " + cert.getType());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keystore, keypass);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keystore);
server = HttpsServer.create(new InetSocketAddress(port), 10);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagerFactory.getKeyManagers(), null/*trustManagerFactory.getTrustManagers()*/, null);
((HttpsServer) server).setHttpsConfigurator(new HttpsConfigurator(sslContext) {
@Override
public void configure(HttpsParameters params) {
SSLEngine engine = sslContext.createSSLEngine();
params.setNeedClientAuth(false);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
SSLParameters defaultSSLParameters = sslContext.getDefaultSSLParameters();
params.setSSLParameters(defaultSSLParameters);
}
});
startSuccessful = true;
} catch (KeyManagementException | NoSuchAlgorithmException e) {
Log.error("WebServer: SSL Context Initialization Failed.");
Log.toLog(this.getClass().getName(), e);
} catch (FileNotFoundException e) {
Log.infoColor(ChatColor.YELLOW + "WebServer: SSL Certificate KeyStore File not Found: " + keyStorePath);
Log.info("No Certificate -> Using Http server for Visualization.");
Log.infoColor(ChatColor.YELLOW + "User Authorization Disabled! (Not possible over http)");
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) {
Log.error("WebServer: SSL Certificate loading Failed.");
Log.toLog(this.getClass().getName(), e);
}
return startSuccessful;
}
private Response getResponse(String target, WebUser user) {
if ("/favicon.ico".equals(target)) {
return new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico");
}
if (usingHttps) {
if (user == null) {
return new PromptAuthorizationResponse();
}
int permLevel = user.getPermLevel(); // Lower number has higher clearance.
int required = getRequiredPermLevel(target, user.getName());
if (permLevel > required) {
return forbiddenResponse(permLevel, required);
}
}
String[] args = target.split("/");
if (args.length < 2) {
return responseNotFound(null);
return rootPageResponse(user);
}
String page = args[1];
switch (page) {
case "favicon.ico":
return new RedirectResponse(null, "https://puu.sh/tK0KL/6aa2ba141b.ico");
case "players":
return new PlayersPageResponse(null, plugin);
return new PlayersPageResponse(plugin);
case "player":
return playerResponse(args, null);
return playerResponse(args);
case "server":
return serverResponse(null);
return serverResponse();
default:
return responseNotFound(null);
return notFoundResponse();
}
}
private Response serverResponse(OutputStream output) {
private ForbiddenResponse forbiddenResponse(int permLevel, int required) {
ForbiddenResponse response403 = new ForbiddenResponse();
String content = "<h1>403 Forbidden - Access Denied</h1>"
+ "<p>Unauthorized User.<br>"
+ "Make sure your user has the correct access level.<br>"
+ "This page requires permission level of " + String.valueOf(required) + ",<br>"
+ "This user has permission level of " + String.valueOf(permLevel) + "</p>";
response403.setContent(content);
return response403;
}
private Response rootPageResponse(WebUser user) {
if (user == null) {
return notFoundResponse();
}
switch (user.getPermLevel()) {
case 0:
return serverResponse();
case 1:
return new PlayersPageResponse(plugin);
case 2:
return playerResponse(new String[]{"", "", user.getName()});
default:
return forbiddenResponse(user.getPermLevel(), 0);
}
}
private Response serverResponse() {
if (!dataReqHandler.checkIfAnalysisIsCached()) {
return new NotFoundResponse(output, "Analysis data was not cached.");
return new NotFoundResponse("Analysis Data was not cached.<br>Use /plan analyze to cache the Data.");
}
return new AnalysisPageResponse(output, dataReqHandler);
return new AnalysisPageResponse(dataReqHandler);
}
private Response playerResponse(String[] args, OutputStream output) {
private Response playerResponse(String[] args) {
if (args.length < 3) {
return new NotFoundResponse(output);
return new NotFoundResponse();
}
String playerName = args[2].trim();
UUID uuid = UUIDUtility.getUUIDOf(playerName);
if (uuid == null) {
return new NotFoundResponse(output, "Player has no UUID");
return new NotFoundResponse("Player has no UUID");
}
if (!dataReqHandler.checkIfCached(uuid)) {
return new NotFoundResponse(output, "Player's data was not cached.");
return new NotFoundResponse("Player's data was not cached.<br>Use /plan inspect " + playerName + " to cache the Data.");
}
return new InspectPageResponse(output, dataReqHandler, uuid);
return new InspectPageResponse(dataReqHandler, uuid);
}
private Response responseNotFound(OutputStream output) {
NotFoundResponse response404 = new NotFoundResponse(output);
private Response notFoundResponse() {
NotFoundResponse response404 = new NotFoundResponse();
String content = "<h1>404 Not Found</h1>"
+ "<p>Make sure you're accessing a link given by a command, Examples:</p>"
+ "<p>" + HtmlUtils.getInspectUrl("<player>") + " or<br>"
+ HtmlUtils.getServerAnalysisUrl() + "</p>";
+ "<p>" + getProtocol() + HtmlUtils.getInspectUrl("<player>") + " or<br>"
+ getProtocol() + HtmlUtils.getServerAnalysisUrl() + "</p>";
response404.setContent(content);
return response404;
}
@ -237,16 +335,58 @@ public class WebServer {
*/
public void stop() {
Log.info(Phrase.WEBSERVER_CLOSE.toString());
shutdown = true;
if (server != null) {
server.stop(0);
}
}
/**
* Used to get the handler for Html content requests.
*
* @return DataRequestHandler used by the WebServer.
*/
public DataRequestHandler getDataReqHandler() {
return dataReqHandler;
}
private int getRequiredPermLevel(String target, String user) {
String[] t = target.split("/");
if (t.length < 2) {
return 100;
}
if (t.length > 3) {
return 0;
}
String page = t[1];
switch (page) {
case "players":
return 1;
case "player":
// /player/ - 404 for perm lvl 1
if (t.length < 3) {
return 1;
}
final String wantedUser = t[2].toLowerCase().trim();
final String theUser = user.trim().toLowerCase();
if (wantedUser.equals(theUser)) {
return 2;
} else {
return 1;
}
default:
return 0;
}
}
public String getProtocol() {
return usingHttps ? "https" : "http";
}
public boolean usingHttps() {
return usingHttps;
}
public boolean isAuthRequired() {
return usingHttps;
}
}

View File

@ -2,16 +2,13 @@ package main.java.com.djrapitops.plan.ui.webserver.response;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class AnalysisPageResponse extends Response {
public AnalysisPageResponse(OutputStream output, DataRequestHandler h) {
super(output);
public AnalysisPageResponse(DataRequestHandler h) {
super.setHeader("HTTP/1.1 200 OK");
super.setContent(h.getAnalysisHtml());
}

View File

@ -1,15 +1,12 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class ForbiddenResponse extends Response {
public ForbiddenResponse(OutputStream output) {
super(output);
public ForbiddenResponse() {
super.setHeader("HTTP/1.1 403 Forbidden");
}
}

View File

@ -2,7 +2,6 @@ package main.java.com.djrapitops.plan.ui.webserver.response;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import java.io.OutputStream;
import java.util.UUID;
/**
@ -11,8 +10,7 @@ import java.util.UUID;
*/
public class InspectPageResponse extends Response {
public InspectPageResponse(OutputStream output, DataRequestHandler h, UUID uuid) {
super(output);
public InspectPageResponse(DataRequestHandler h, UUID uuid) {
super.setHeader("HTTP/1.1 200 OK");
super.setContent(h.getInspectHtml(uuid));
}

View File

@ -2,16 +2,13 @@ package main.java.com.djrapitops.plan.ui.webserver.response;
import main.java.com.djrapitops.plan.ui.html.Html;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class InternalErrorResponse extends Response {
public InternalErrorResponse(OutputStream output, Throwable e, String cause) {
super(output);
public InternalErrorResponse(Throwable e, String cause) {
super.setHeader("HTTP/1.1 500 Internal Error");
StringBuilder content = new StringBuilder();
content.append("<h1>500 Internal Error occurred</h1>");

View File

@ -4,7 +4,6 @@ import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import java.io.FileNotFoundException;
import java.io.OutputStream;
/**
* @author Rsl1122
@ -12,8 +11,7 @@ import java.io.OutputStream;
*/
public class JavaScriptResponse extends Response {
public JavaScriptResponse(OutputStream output, String resource) {
super(output);
public JavaScriptResponse(String resource) {
super.setHeader("HTTP/1.1 200 OK");
try {
super.setContent(HtmlUtils.getStringFromResource(resource));

View File

@ -1,21 +1,17 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class NotFoundResponse extends Response {
public NotFoundResponse(OutputStream output) {
super(output);
public NotFoundResponse() {
super.setHeader("HTTP/1.1 404 Not Found");
super.setContent("<h1>404 Not Found</h1><p>Page does not exist.</p>");
}
public NotFoundResponse(OutputStream output, String msg) {
super(output);
public NotFoundResponse(String msg) {
super.setHeader("HTTP/1.1 404 Not Found");
super.setContent("<h1>404 Not Found</h1><p>" + msg + "</p>");
}

View File

@ -6,7 +6,6 @@ import main.java.com.djrapitops.plan.ui.html.Html;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.comparators.UserDataNameComparator;
import java.io.OutputStream;
import java.util.List;
/**
@ -15,14 +14,13 @@ import java.util.List;
*/
public class PlayersPageResponse extends Response {
public PlayersPageResponse(OutputStream output, Plan plugin) {
super(output);
public PlayersPageResponse(Plan plugin) {
super.setHeader("HTTP/1.1 200 OK");
super.setContent(buildContent(plugin.getInspectCache().getCachedUserData()));
}
public static String buildContent(List<UserData> cached) {
StringBuilder html = new StringBuilder("<h1>Cached Players</h1><p>");
StringBuilder html = new StringBuilder("<!DOCTYPE html><html><body><h1>Cached Players</h1><p>");
int size = cached.size();
html.append(size)
@ -39,7 +37,7 @@ public class PlayersPageResponse extends Response {
}
i++;
}
html.append("</tr></table>");
html.append("</tr></table></body></html>");
return html.toString();
}
}

View File

@ -1,17 +1,14 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class PromptAuthorizationResponse extends Response {
public PromptAuthorizationResponse(OutputStream output) {
super(output);
public PromptAuthorizationResponse() {
super.setHeader("HTTP/1.1 401 Access Denied\r\n"
+ "WWW-Authenticate: Basic realm=\"Analysis\";");
+ "WWW-Authenticate: Basic realm=\"/\";");
super.setContent("<h1>401 Unauthorized</h1><p>Authentication Failed.<br>"
+ "- Ensure you have registered a user with <b>/plan register</b><br>"
+ "- Check that the username and password are correct<br>"

View File

@ -1,15 +1,12 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public class RedirectResponse extends Response {
public RedirectResponse(OutputStream output, String direct) {
super(output);
public RedirectResponse(String direct) {
super.setHeader("HTTP/1.1 302 Found");
super.setContent("Location: " + direct);
}

View File

@ -1,39 +1,18 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author Rsl1122
* @since 3.5.2
*/
public abstract class Response {
private final OutputStream output;
private String header;
private String content;
/**
* Class Constructor.
*
* @param output Website OutputStream to write the response to.
*/
public Response(OutputStream output) {
this.output = output;
}
/**
* Writes the HTML to the OutputStream according to the requested page.
*
* @throws IOException
*/
public void sendStaticResource() throws IOException {
String response = getResponse();
// Log.debug("Response: " + response); // Responses should not be logged, html content large.
output.write(response.getBytes());
output.flush();
public Response() {
}
public String getResponse() {

View File

@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.utilities;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.ui.html.Html;
import main.java.com.djrapitops.plan.ui.webserver.WebServer;
import java.io.File;
import java.io.FileNotFoundException;
@ -73,28 +74,44 @@ public class HtmlUtils {
* @return
*/
public static String getServerAnalysisUrlWithProtocol() {
return Settings.LINK_PROTOCOL.toString() + ":" + getServerAnalysisUrl();
return getProtocol() + ":" + getServerAnalysisUrl();
}
/**
* @return
*/
public static String getServerAnalysisUrl() {
int port = Settings.WEBSERVER_PORT.getNumber();
String ip = Plan.getInstance().getVariable().getIp() + ":" + port;
boolean useAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue();
if (useAlternativeIP) {
ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", String.valueOf(port));
}
String ip = getIP();
return "//" + ip + "/server";
}
/**
* Used to get the WebServer's IP with Port.
*
* @return For example 127.0.0.1:8804
*/
public static String getIP() {
int port = Settings.WEBSERVER_PORT.getNumber();
String ip;
if (Settings.SHOW_ALTERNATIVE_IP.isTrue()) {
ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", String.valueOf(port));
} else {
ip = Plan.getInstance().getVariable().getIp() + ":" + port;
}
return ip;
}
private static String getProtocol() {
WebServer uiServer = Plan.getInstance().getUiServer();
return uiServer.isEnabled() ? uiServer.getProtocol() : Settings.LINK_PROTOCOL.toString();
}
/**
* @param playerName
* @return
*/
public static String getInspectUrlWithProtocol(String playerName) {
return Settings.LINK_PROTOCOL.toString() + ":" + getInspectUrl(playerName);
return getProtocol() + ":" + getInspectUrl(playerName);
}
/**
@ -102,12 +119,7 @@ public class HtmlUtils {
* @return
*/
public static String getInspectUrl(String playerName) {
int port = Settings.WEBSERVER_PORT.getNumber();
String ip = Plan.getInstance().getVariable().getIp() + ":" + port;
boolean useAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue();
if (useAlternativeIP) {
ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", String.valueOf(port));
}
String ip = getIP();
return "//" + ip + "/player/" + playerName;
}

View File

@ -34,7 +34,7 @@ Settings:
InternalIP: 0.0.0.0
ShowAlternativeServerIP: false
AlternativeIP: your.ip.here:%port%
LinkProtocol: http
ExternalWebServerLinkProtocol: http
Security:
DisplayIPsAndUUIDs: true
Certificate: