Finished writing webserver functionality:

- Http server if cert not found
- Automatic path based on level
- Cleaned Responses a bit
- Using own Authentication
- Commands notify about missing user only when using auth
- New settings: UsingExternalWebserver, ExternalWebServerLinkProtocol (renamed LinkProtocol)

Removed TODO note from NicknamesTable
This commit is contained in:
Rsl1122 2017-07-29 20:01:08 +03:00
parent ed555cce76
commit e6fca61a59
18 changed files with 328 additions and 260 deletions

View File

@ -28,6 +28,7 @@ public enum Settings {
SECURITY_IP_UUID("Settings.WebServer.Security.DisplayIPsAndUUIDs"), SECURITY_IP_UUID("Settings.WebServer.Security.DisplayIPsAndUUIDs"),
GRAPH_PLAYERS_USEMAXPLAYERS_SCALE("Customization.Graphs.PlayersOnlineGraph.UseMaxPlayersAsScale"), GRAPH_PLAYERS_USEMAXPLAYERS_SCALE("Customization.Graphs.PlayersOnlineGraph.UseMaxPlayersAsScale"),
PLAYERLIST_SHOW_IMAGES("Customization.SmallHeadImagesOnAnalysisPlayerlist"), PLAYERLIST_SHOW_IMAGES("Customization.SmallHeadImagesOnAnalysisPlayerlist"),
EXTERNAL_WEBSERVER("Settings.WebServer.UsingExternalWebServer"),
// Integer // Integer
ANALYSIS_MINUTES_FOR_ACTIVE("Settings.Analysis.MinutesPlayedUntilConsidiredActive"), ANALYSIS_MINUTES_FOR_ACTIVE("Settings.Analysis.MinutesPlayedUntilConsidiredActive"),
SAVE_CACHE_MIN("Settings.Cache.DataCache.SaveEveryXMinutes"), SAVE_CACHE_MIN("Settings.Cache.DataCache.SaveEveryXMinutes"),
@ -53,7 +54,7 @@ public enum Settings {
WEBSERVER_CERTIFICATE_KEYPASS("Settings.WebServer.Security.Certificate.KeyPass"), WEBSERVER_CERTIFICATE_KEYPASS("Settings.WebServer.Security.Certificate.KeyPass"),
WEBSERVER_CERTIFICATE_STOREPASS("Settings.WebServer.Security.Certificate.KeyPass"), WEBSERVER_CERTIFICATE_STOREPASS("Settings.WebServer.Security.Certificate.KeyPass"),
WEBSERVER_CERTIFICATE_ALIAS("Settings.WebServer.Security.Certificate.Alias"), WEBSERVER_CERTIFICATE_ALIAS("Settings.WebServer.Security.Certificate.Alias"),
LINK_PROTOCOL("Settings.WebServer.LinkProtocol"), LINK_PROTOCOL("Settings.WebServer.ExternalWebServerLinkProtocol"),
// //
SERVER_NAME("Customization.ServerName"), SERVER_NAME("Customization.ServerName"),
// //

View File

@ -68,6 +68,7 @@ public class AnalyzeCommand extends SubCommand {
} }
sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + ""); sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + "");
if (plugin.getUiServer().isAuthRequired()) {
plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") { plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") {
@Override @Override
public void run() { public void run() {
@ -85,6 +86,7 @@ public class AnalyzeCommand extends SubCommand {
} }
} }
}).runTaskAsynchronously(); }).runTaskAsynchronously();
}
updateCache(); updateCache();
runMessageSenderTask(sender); runMessageSenderTask(sender);
return true; return true;

View File

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

View File

@ -199,15 +199,17 @@ public class NicknamesTable extends Table {
lastNicks.put(id, nickname); lastNicks.put(id, nickname);
} }
} }
for (Map.Entry<Integer, String> entry : lastNicks.entrySet()) {
//TODO figure out what the heck that method does @Rsl1122 Integer id = entry.getKey();
for (Map.Entry<Integer, String> entrySet : lastNicks.entrySet()) { String lastNick = entry.getValue();
Integer id = entrySet.getKey();
String lastNick = entrySet.getValue();
List<String> list = nicks.get(id); 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; return nicks;

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,14 +1,20 @@
package main.java.com.djrapitops.plan.ui.webserver; package main.java.com.djrapitops.plan.ui.webserver;
import com.djrapitops.plugin.utilities.Verify;
import com.sun.net.httpserver.*; import com.sun.net.httpserver.*;
import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings; 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.html.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.response.*; import main.java.com.djrapitops.plan.ui.webserver.response.*;
import main.java.com.djrapitops.plan.utilities.HtmlUtils; 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 main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import org.bukkit.ChatColor;
import javax.net.ssl.*; import javax.net.ssl.*;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -20,6 +26,8 @@ import java.net.URI;
import java.security.*; import java.security.*;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -33,7 +41,8 @@ public class WebServer {
private boolean enabled = false; private boolean enabled = false;
private HttpServer server; private HttpServer server;
private final int port; private final int port;
private boolean shutdown;
private boolean usingHttps;
/** /**
* Class Constructor. * Class Constructor.
@ -45,7 +54,6 @@ public class WebServer {
public WebServer(Plan plugin) { public WebServer(Plan plugin) {
this.plugin = plugin; this.plugin = plugin;
this.port = Settings.WEBSERVER_PORT.getNumber(); this.port = Settings.WEBSERVER_PORT.getNumber();
shutdown = false;
dataReqHandler = new DataRequestHandler(plugin); dataReqHandler = new DataRequestHandler(plugin);
} }
@ -59,6 +67,139 @@ public class WebServer {
} }
Log.info(Phrase.WEBSERVER_INIT.toString()); Log.info(Phrase.WEBSERVER_INIT.toString());
try { try {
usingHttps = startHttpsServer();
Log.debug(usingHttps ? "Https Start Successful." : "Https Start Failed.");
if (!usingHttps) {
server = HttpServer.create();
return;
// TODO Http Redirect Server
// } else {
// HttpServer protocolUpdateServer = HttpServer.create(new InetSocketAddress(port), 10);
// protocolUpdateServer.setExecutor(Executors.newSingleThreadExecutor());
//
// protocolUpdateServer.createContext("/", new HttpHandler() {
// @Override
// public void handle(HttpExchange exchange) throws IOException {
// try {
// URI uri = exchange.getRequestURI();
// Headers requestHeaders = exchange.getRequestHeaders();
// List<String> host = requestHeaders.get("Host");
// String currentAddress;
// if (Verify.isEmpty(host)) {
// currentAddress = HtmlUtils.getIP();
// } else {
// currentAddress = host.get(0);
// }
// Headers responseHeaders = exchange.getResponseHeaders();
// String newAddress = "https://" + currentAddress + uri.toASCIIString();
// responseHeaders.set("Location", newAddress);
// Log.debug("Redirected http " + uri + " to new address: " + newAddress);
// exchange.sendResponseHeaders(301, 0);
// exchange.getResponseBody().close();
// } finally {
// exchange.close();
// }
//
// }
// });
// protocolUpdateServer.start();
}
HttpContext context = server.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange xchange) throws IOException {
OutputStream os = null;
try {
HttpsExchange exchange = (HttpsExchange) xchange;
URI uri = exchange.getRequestURI();
String target = uri.toString();
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());
os = exchange.getResponseBody();
os.write(content.getBytes());
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
} finally {
MiscUtils.close(os);
xchange.close();
}
}
});
server.setExecutor(Executors.newSingleThreadExecutor());
server.start();
enabled = true;
Log.info(Phrase.WEBSERVER_RUNNING.parse(String.valueOf(server.getAddress().getPort())));
} catch (IllegalArgumentException | IllegalStateException | IOException e) {
Log.toLog(this.getClass().getName(), e);
enabled = false;
}
}
private WebUser getUser(Headers requestHeaders) {
try {
List<String> authorization = requestHeaders.get("Authorization");
if (Verify.isEmpty(authorization)) {
Log.debug("WebServer: Authorization not Found");
return null;
}
Log.debug("WebServer: Found Authorization");
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];
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(); String keyStorePath = Settings.WEBSERVER_CERTIFICATE_PATH.toString();
if (!keyStorePath.contains(":")) { if (!keyStorePath.contains(":")) {
keyStorePath = plugin.getDataFolder() + keyStorePath; keyStorePath = plugin.getDataFolder() + keyStorePath;
@ -107,115 +248,99 @@ public class WebServer {
Log.error("!--------!---------!---------!"); Log.error("!--------!---------!---------!");
Log.error("WebServer: SSL Certificate KeyStore File not Found: " + keyStorePath); Log.error("WebServer: SSL Certificate KeyStore File not Found: " + keyStorePath);
Log.error("!--------!---------!---------!"); Log.error("!--------!---------!---------!");
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) { } catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) {
Log.error("WebServer: SSL Certificate loading Failed."); Log.error("WebServer: SSL Certificate loading Failed.");
Log.toLog(this.getClass().getName(), e); Log.toLog(this.getClass().getName(), e);
} }
return startSuccessful;
Log.debug("Start Successful: " + startSuccessful);
if (!startSuccessful) {
return; // TODO Http Server
} }
Log.debug("Create server context"); private Response getResponse(String target, WebUser user) {
HttpContext context = server.createContext("/", new HttpHandler() { if (usingHttps) {
@Override if (user == null) {
public void handle(HttpExchange xghng) throws IOException { return new PromptAuthorizationResponse();
HttpsExchange exchange = (HttpsExchange) xghng;
try {
URI uri = exchange.getRequestURI();
String target = uri.toString();
Response response = getResponse(target);
String content = response.getContent();
exchange.sendResponseHeaders(response.getCode(), content.length());
OutputStream os = exchange.getResponseBody();
os.write(content.getBytes());
os.close();
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
}
}
});
if (startSuccessful) {
context.setAuthenticator(new Authenticator(plugin, "/"));
}
server.setExecutor(Executors.newSingleThreadExecutor());
server.start();
enabled = true;
Log.info(Phrase.WEBSERVER_RUNNING.parse(String.valueOf(server.getAddress().getPort())));
} catch (IllegalArgumentException | IllegalStateException | IOException e) {
Log.toLog(this.getClass().getName(), e);
enabled = false;
}
} }
// if (!request.hasAuthorization()) { if (!isAuthorized(target, user)) {
// return new PromptAuthorizationResponse(output); return forbiddenResponse();
// } }
// 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 Response getResponse(String target) {
String[] args = target.split("/"); String[] args = target.split("/");
if (args.length < 2) { if (args.length < 2) {
return responseNotFound(null); return rootPageResponse(user);
} }
String page = args[1]; String page = args[1];
switch (page) { switch (page) {
case "favicon.ico": case "favicon.ico":
return new RedirectResponse(null, "https://puu.sh/tK0KL/6aa2ba141b.ico"); return new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico");
case "players": case "players":
return new PlayersPageResponse(null, plugin); return new PlayersPageResponse(plugin);
case "player": case "player":
return playerResponse(args, null); return playerResponse(args);
case "server": case "server":
return serverResponse(null); return serverResponse();
default: default:
return responseNotFound(null); return notFoundResponse();
} }
} }
private Response serverResponse(OutputStream output) { private ForbiddenResponse forbiddenResponse() {
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>"
+ "You can use /plan web check <username> to check the permission level.</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();
}
}
private Response serverResponse() {
if (!dataReqHandler.checkIfAnalysisIsCached()) { 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) { if (args.length < 3) {
return new NotFoundResponse(output); return new NotFoundResponse();
} }
String playerName = args[2].trim(); String playerName = args[2].trim();
UUID uuid = UUIDUtility.getUUIDOf(playerName); UUID uuid = UUIDUtility.getUUIDOf(playerName);
if (uuid == null) { if (uuid == null) {
return new NotFoundResponse(output, "Player has no UUID"); return new NotFoundResponse("Player has no UUID");
} }
if (!dataReqHandler.checkIfCached(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) { private Response notFoundResponse() {
NotFoundResponse response404 = new NotFoundResponse(output); NotFoundResponse response404 = new NotFoundResponse();
String content = "<h1>404 Not Found</h1>" String content = "<h1>404 Not Found</h1>"
+ "<p>Make sure you're accessing a link given by a command, Examples:</p>" + "<p>Make sure you're accessing a link given by a command, Examples:</p>"
+ "<p>" + HtmlUtils.getInspectUrl("<player>") + " or<br>" + "<p>" + getProtocol() + HtmlUtils.getInspectUrl("<player>") + " or<br>"
+ HtmlUtils.getServerAnalysisUrl() + "</p>"; + getProtocol() + HtmlUtils.getServerAnalysisUrl() + "</p>";
response404.setContent(content); response404.setContent(content);
return response404; return response404;
} }
@ -232,16 +357,55 @@ public class WebServer {
*/ */
public void stop() { public void stop() {
Log.info(Phrase.WEBSERVER_CLOSE.toString()); Log.info(Phrase.WEBSERVER_CLOSE.toString());
shutdown = true;
if (server != null) { if (server != null) {
server.stop(0); server.stop(0);
} }
} }
/** /**
* Used to get the handler for Html content requests.
*
* @return DataRequestHandler used by the WebServer. * @return DataRequestHandler used by the WebServer.
*/ */
public DataRequestHandler getDataReqHandler() { public DataRequestHandler getDataReqHandler() {
return dataReqHandler; return dataReqHandler;
} }
private boolean isAuthorized(String target, WebUser user) {
int permLevel = user.getPermLevel(); // Lower number has higher clearance.
int required = getRequiredPermLevel(target, user.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;
}
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 main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
* @since 3.5.2 * @since 3.5.2
*/ */
public class AnalysisPageResponse extends Response { public class AnalysisPageResponse extends Response {
public AnalysisPageResponse(OutputStream output, DataRequestHandler h) { public AnalysisPageResponse(DataRequestHandler h) {
super(output);
super.setHeader("HTTP/1.1 200 OK"); super.setHeader("HTTP/1.1 200 OK");
super.setContent(h.getAnalysisHtml()); super.setContent(h.getAnalysisHtml());
} }

View File

@ -1,15 +1,12 @@
package main.java.com.djrapitops.plan.ui.webserver.response; package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
* @since 3.5.2 * @since 3.5.2
*/ */
public class ForbiddenResponse extends Response { public class ForbiddenResponse extends Response {
public ForbiddenResponse(OutputStream output) { public ForbiddenResponse() {
super(output);
super.setHeader("HTTP/1.1 403 Forbidden"); 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 main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import java.io.OutputStream;
import java.util.UUID; import java.util.UUID;
/** /**
@ -11,8 +10,7 @@ import java.util.UUID;
*/ */
public class InspectPageResponse extends Response { public class InspectPageResponse extends Response {
public InspectPageResponse(OutputStream output, DataRequestHandler h, UUID uuid) { public InspectPageResponse(DataRequestHandler h, UUID uuid) {
super(output);
super.setHeader("HTTP/1.1 200 OK"); super.setHeader("HTTP/1.1 200 OK");
super.setContent(h.getInspectHtml(uuid)); 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 main.java.com.djrapitops.plan.ui.html.Html;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
* @since 3.5.2 * @since 3.5.2
*/ */
public class InternalErrorResponse extends Response { public class InternalErrorResponse extends Response {
public InternalErrorResponse(OutputStream output, Throwable e, String cause) { public InternalErrorResponse(Throwable e, String cause) {
super(output);
super.setHeader("HTTP/1.1 500 Internal Error"); super.setHeader("HTTP/1.1 500 Internal Error");
StringBuilder content = new StringBuilder(); StringBuilder content = new StringBuilder();
content.append("<h1>500 Internal Error occurred</h1>"); 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 main.java.com.djrapitops.plan.utilities.HtmlUtils;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
@ -12,8 +11,7 @@ import java.io.OutputStream;
*/ */
public class JavaScriptResponse extends Response { public class JavaScriptResponse extends Response {
public JavaScriptResponse(OutputStream output, String resource) { public JavaScriptResponse(String resource) {
super(output);
super.setHeader("HTTP/1.1 200 OK"); super.setHeader("HTTP/1.1 200 OK");
try { try {
super.setContent(HtmlUtils.getStringFromResource(resource)); super.setContent(HtmlUtils.getStringFromResource(resource));

View File

@ -1,21 +1,17 @@
package main.java.com.djrapitops.plan.ui.webserver.response; package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
* @since 3.5.2 * @since 3.5.2
*/ */
public class NotFoundResponse extends Response { public class NotFoundResponse extends Response {
public NotFoundResponse(OutputStream output) { public NotFoundResponse() {
super(output);
super.setHeader("HTTP/1.1 404 Not Found"); super.setHeader("HTTP/1.1 404 Not Found");
super.setContent("<h1>404 Not Found</h1><p>Page does not exist.</p>"); super.setContent("<h1>404 Not Found</h1><p>Page does not exist.</p>");
} }
public NotFoundResponse(OutputStream output, String msg) { public NotFoundResponse(String msg) {
super(output);
super.setHeader("HTTP/1.1 404 Not Found"); super.setHeader("HTTP/1.1 404 Not Found");
super.setContent("<h1>404 Not Found</h1><p>" + msg + "</p>"); 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.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.comparators.UserDataNameComparator; import main.java.com.djrapitops.plan.utilities.comparators.UserDataNameComparator;
import java.io.OutputStream;
import java.util.List; import java.util.List;
/** /**
@ -15,8 +14,7 @@ import java.util.List;
*/ */
public class PlayersPageResponse extends Response { public class PlayersPageResponse extends Response {
public PlayersPageResponse(OutputStream output, Plan plugin) { public PlayersPageResponse(Plan plugin) {
super(output);
super.setHeader("HTTP/1.1 200 OK"); super.setHeader("HTTP/1.1 200 OK");
super.setContent(buildContent(plugin.getInspectCache().getCachedUserData())); super.setContent(buildContent(plugin.getInspectCache().getCachedUserData()));
} }

View File

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

View File

@ -1,39 +1,18 @@
package main.java.com.djrapitops.plan.ui.webserver.response; package main.java.com.djrapitops.plan.ui.webserver.response;
import java.io.IOException;
import java.io.OutputStream;
/** /**
* @author Rsl1122 * @author Rsl1122
* @since 3.5.2 * @since 3.5.2
*/ */
public abstract class Response { public abstract class Response {
private final OutputStream output;
private String header; private String header;
private String content; private String content;
/** /**
* Class Constructor. * Class Constructor.
*
* @param output Website OutputStream to write the response to.
*/ */
public Response(OutputStream output) { public Response() {
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 String getResponse() { public String getResponse() {

View File

@ -73,28 +73,43 @@ public class HtmlUtils {
* @return * @return
*/ */
public static String getServerAnalysisUrlWithProtocol() { public static String getServerAnalysisUrlWithProtocol() {
return Settings.LINK_PROTOCOL.toString() + ":" + getServerAnalysisUrl(); return getProtocol() + ":" + getServerAnalysisUrl();
} }
/** /**
* @return * @return
*/ */
public static String getServerAnalysisUrl() { public static String getServerAnalysisUrl() {
int port = Settings.WEBSERVER_PORT.getNumber(); String ip = getIP();
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));
}
return "//" + ip + "/server"; 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() {
return Settings.EXTERNAL_WEBSERVER.isTrue() ? Settings.LINK_PROTOCOL.toString() : Plan.getInstance().getUiServer().getProtocol();
}
/** /**
* @param playerName * @param playerName
* @return * @return
*/ */
public static String getInspectUrlWithProtocol(String playerName) { public static String getInspectUrlWithProtocol(String playerName) {
return Settings.LINK_PROTOCOL.toString() + ":" + getInspectUrl(playerName); return getProtocol() + ":" + getInspectUrl(playerName);
} }
/** /**
@ -102,12 +117,7 @@ public class HtmlUtils {
* @return * @return
*/ */
public static String getInspectUrl(String playerName) { public static String getInspectUrl(String playerName) {
int port = Settings.WEBSERVER_PORT.getNumber(); String ip = getIP();
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));
}
return "//" + ip + "/player/" + playerName; return "//" + ip + "/player/" + playerName;
} }

View File

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