mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-24 09:01:41 +01:00
Delete Sun Webserver implementation
This commit is contained in:
parent
2aa189798d
commit
f8652ad1b9
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.webserver.http;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.URIPath;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.URIQuery;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.AuthenticationExtractor;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.Cookie;
|
||||
import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfiguration;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import org.apache.commons.text.TextStringBuilder;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SunInternalRequest implements InternalRequest {
|
||||
|
||||
private final HttpExchange exchange;
|
||||
private final WebserverConfiguration webserverConfiguration;
|
||||
private final AuthenticationExtractor authenticationExtractor;
|
||||
|
||||
public SunInternalRequest(HttpExchange exchange, WebserverConfiguration webserverConfiguration, AuthenticationExtractor authenticationExtractor) {
|
||||
this.exchange = exchange;
|
||||
this.webserverConfiguration = webserverConfiguration;
|
||||
this.authenticationExtractor = authenticationExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessAddressFromSocketIp() {
|
||||
return exchange.getRemoteAddress().getAddress().getHostAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessAddressFromHeader() {
|
||||
return exchange.getRequestHeaders().getFirst("X-Forwarded-For");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestedURIString() {
|
||||
return exchange.getRequestURI().toASCIIString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request toRequest() {
|
||||
return buildRequest(exchange);
|
||||
}
|
||||
|
||||
private Request buildRequest(HttpExchange exchange) {
|
||||
String requestMethod = exchange.getRequestMethod();
|
||||
URIPath path = new URIPath(exchange.getRequestURI().getPath());
|
||||
URIQuery query = new URIQuery(exchange.getRequestURI().getRawQuery());
|
||||
byte[] requestBody = readRequestBody(exchange);
|
||||
WebUser user = getWebUser(webserverConfiguration, authenticationExtractor);
|
||||
Map<String, String> headers = getRequestHeaders(exchange);
|
||||
return new Request(requestMethod, path, query, user, headers, requestBody);
|
||||
}
|
||||
|
||||
private byte[] readRequestBody(HttpExchange exchange) {
|
||||
try (ByteArrayOutputStream buf = new ByteArrayOutputStream(512)) {
|
||||
int b;
|
||||
while ((b = exchange.getRequestBody().read()) != -1) {
|
||||
buf.write((byte) b);
|
||||
}
|
||||
return buf.toByteArray();
|
||||
} catch (IOException ignored) {
|
||||
// requestBody stays empty
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getRequestHeaders(HttpExchange exchange) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
for (Map.Entry<String, List<String>> e : exchange.getRequestHeaders().entrySet()) {
|
||||
List<String> value = e.getValue();
|
||||
headers.put(e.getKey(), new TextStringBuilder().appendWithSeparators(value, ";").build());
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> getCookies() {
|
||||
List<String> textCookies = exchange.getRequestHeaders().get("Cookie");
|
||||
List<Cookie> cookies = new ArrayList<>();
|
||||
if (textCookies != null && !textCookies.isEmpty()) {
|
||||
String[] separated = new TextStringBuilder().appendWithSeparators(textCookies, ";").build().split(";");
|
||||
for (String textCookie : separated) {
|
||||
cookies.add(new Cookie(textCookie));
|
||||
}
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.webserver.http;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.webserver.Addresses;
|
||||
import com.djrapitops.plan.delivery.webserver.ResponseResolver;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.AuthenticationExtractor;
|
||||
import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfiguration;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.PluginSettings;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import net.playeranalytics.plugin.server.PluginLogger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* HttpHandler for WebServer request management.
|
||||
*
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Singleton
|
||||
public class SunRequestHandler implements HttpHandler {
|
||||
|
||||
private final PlanConfig config;
|
||||
private final Addresses addresses;
|
||||
private final WebserverConfiguration webserverConfiguration;
|
||||
private final AuthenticationExtractor authenticationExtractor;
|
||||
private final ResponseResolver responseResolver;
|
||||
private final RequestHandler requestHandler;
|
||||
private final PluginLogger logger;
|
||||
private final ErrorLogger errorLogger;
|
||||
|
||||
@Inject
|
||||
public SunRequestHandler(
|
||||
PlanConfig config,
|
||||
Addresses addresses,
|
||||
WebserverConfiguration webserverConfiguration,
|
||||
AuthenticationExtractor authenticationExtractor,
|
||||
ResponseResolver responseResolver,
|
||||
RequestHandler requestHandler,
|
||||
PluginLogger logger,
|
||||
ErrorLogger errorLogger
|
||||
) {
|
||||
this.config = config;
|
||||
this.addresses = addresses;
|
||||
this.webserverConfiguration = webserverConfiguration;
|
||||
this.authenticationExtractor = authenticationExtractor;
|
||||
this.responseResolver = responseResolver;
|
||||
this.requestHandler = requestHandler;
|
||||
this.logger = logger;
|
||||
this.errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
InternalRequest internalRequest = new SunInternalRequest(exchange, webserverConfiguration, authenticationExtractor);
|
||||
Response response = requestHandler.getResponse(internalRequest);
|
||||
new SunResponseSender(addresses, exchange, response).send();
|
||||
} catch (Exception e) {
|
||||
if (config.isTrue(PluginSettings.DEV_MODE)) {
|
||||
logger.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:");
|
||||
errorLogger.warn(e, ErrorContext.builder()
|
||||
.whatToDo("THIS ERROR IS ONLY LOGGED IN DEV MODE")
|
||||
.related(exchange.getRequestMethod(), exchange.getRemoteAddress(), exchange.getRequestHeaders(), exchange.getResponseHeaders(), exchange.getRequestURI())
|
||||
.build());
|
||||
}
|
||||
} finally {
|
||||
exchange.close();
|
||||
}
|
||||
}
|
||||
|
||||
public ResponseResolver getResponseResolver() {
|
||||
return responseResolver;
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.webserver.http;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.webserver.Addresses;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* Utility for sending a Response to HttpExchange.
|
||||
*
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class SunResponseSender {
|
||||
|
||||
private final Addresses addresses;
|
||||
private final HttpExchange exchange;
|
||||
private final Response response;
|
||||
|
||||
public SunResponseSender(Addresses addresses, HttpExchange exchange, Response response) {
|
||||
this.addresses = addresses;
|
||||
this.exchange = exchange;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public void send() throws IOException {
|
||||
setResponseHeaders();
|
||||
if ("HEAD".equals(exchange.getRequestMethod()) || response.getCode() == 204) {
|
||||
sendHeadResponse();
|
||||
} else if ("bytes".equalsIgnoreCase(response.getHeaders().get("Accept-Ranges"))) {
|
||||
sendRawBytes();
|
||||
} else {
|
||||
sendCompressed();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendHeadResponse() throws IOException {
|
||||
try {
|
||||
exchange.getResponseHeaders().remove("Content-Length");
|
||||
beginSend();
|
||||
} finally {
|
||||
exchange.getRequestBody().close();
|
||||
}
|
||||
}
|
||||
|
||||
private void setResponseHeaders() {
|
||||
Headers headers = exchange.getResponseHeaders();
|
||||
|
||||
Map<String, String> responseHeaders = response.getHeaders();
|
||||
correctRedirect(responseHeaders);
|
||||
|
||||
for (Map.Entry<String, String> header : responseHeaders.entrySet()) {
|
||||
headers.set(header.getKey(), header.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void correctRedirect(Map<String, String> responseHeaders) {
|
||||
String redirect = responseHeaders.get("Location");
|
||||
if (redirect != null) {
|
||||
if (redirect.startsWith("http") || !redirect.startsWith("/")) return;
|
||||
addresses.getAccessAddress().ifPresent(address -> responseHeaders.put("Location", address + redirect));
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCompressed() throws IOException {
|
||||
exchange.getResponseHeaders().set("Content-Encoding", "gzip");
|
||||
beginSend();
|
||||
try (OutputStream out = new GZIPOutputStream(exchange.getResponseBody())) {
|
||||
send(out);
|
||||
}
|
||||
}
|
||||
|
||||
private void beginSend() throws IOException {
|
||||
String length = response.getHeaders().get("Content-Length");
|
||||
if (length == null || "0".equals(length)) {
|
||||
exchange.getResponseHeaders().remove("Content-Length");
|
||||
}
|
||||
// Return a content length of -1 for HTTP code 204 (No content)
|
||||
// and HEAD requests to avoid warning messages.
|
||||
exchange.sendResponseHeaders(response.getCode(), (response.getCode() == 204 || "HEAD".equals(exchange.getRequestMethod()) || length == null) ? -1 : Long.parseLong(length));
|
||||
}
|
||||
|
||||
private void sendRawBytes() throws IOException {
|
||||
beginSend();
|
||||
try (OutputStream out = exchange.getResponseBody()) {
|
||||
send(out);
|
||||
}
|
||||
}
|
||||
|
||||
private void send(OutputStream out) throws IOException {
|
||||
try (
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(response.getBytes())
|
||||
) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int count;
|
||||
while ((count = bis.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,314 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.webserver.http;
|
||||
|
||||
import com.djrapitops.plan.delivery.webserver.Addresses;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.PluginSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.settings.locale.lang.PluginLang;
|
||||
import com.djrapitops.plan.storage.file.PlanFiles;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import com.sun.net.httpserver.HttpsConfigurator;
|
||||
import com.sun.net.httpserver.HttpsParameters;
|
||||
import com.sun.net.httpserver.HttpsServer;
|
||||
import net.playeranalytics.plugin.server.PluginLogger;
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Singleton
|
||||
public class SunWebServer implements WebServer {
|
||||
|
||||
private final Locale locale;
|
||||
private final PlanFiles files;
|
||||
private final PlanConfig config;
|
||||
|
||||
private final Addresses addresses;
|
||||
private final SunRequestHandler requestHandler;
|
||||
|
||||
private final PluginLogger logger;
|
||||
private final ErrorLogger errorLogger;
|
||||
|
||||
private int port;
|
||||
private boolean enabled = false;
|
||||
private HttpServer server;
|
||||
|
||||
private boolean usingHttps = false;
|
||||
|
||||
@Inject
|
||||
public SunWebServer(
|
||||
Locale locale,
|
||||
PlanFiles files,
|
||||
PlanConfig config,
|
||||
Addresses addresses,
|
||||
PluginLogger logger,
|
||||
ErrorLogger errorLogger,
|
||||
SunRequestHandler requestHandler
|
||||
) {
|
||||
this.locale = locale;
|
||||
this.files = files;
|
||||
this.config = config;
|
||||
this.addresses = addresses;
|
||||
|
||||
this.requestHandler = requestHandler;
|
||||
|
||||
this.logger = logger;
|
||||
this.errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
this.port = config.get(WebserverSettings.PORT);
|
||||
|
||||
initServer();
|
||||
|
||||
if (addresses.getAccessAddress().isEmpty()) {
|
||||
logger.warn(locale.getString(PluginLang.ENABLE_NOTIFY_BAD_IP));
|
||||
}
|
||||
|
||||
if (!isEnabled()) {
|
||||
if (config.isTrue(WebserverSettings.DISABLED)) {
|
||||
logger.info(locale.getString(PluginLang.ENABLE_NOTIFY_WEB_SERVER_DISABLED));
|
||||
} else {
|
||||
logger.error(locale.getString(PluginLang.WEB_SERVER_FAIL_PORT_BIND, port));
|
||||
}
|
||||
} else if (config.isTrue(WebserverSettings.IP_WHITELIST)) {
|
||||
logger.info(locale.getString(PluginLang.WEB_SERVER_NOTIFY_IP_WHITELIST));
|
||||
}
|
||||
|
||||
requestHandler.getResponseResolver().registerPages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the WebServer in a new Thread Pool.
|
||||
*/
|
||||
private void initServer() {
|
||||
if (config.isTrue(WebserverSettings.DISABLED)) {
|
||||
// WebServer has been disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
// Server is already enabled stop code
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
usingHttps = startHttpsServer();
|
||||
|
||||
if (!usingHttps) {
|
||||
logger.info("§e" + locale.getString(PluginLang.WEB_SERVER_NOTIFY_HTTP_USER_AUTH));
|
||||
server = HttpServer.create(new InetSocketAddress(config.get(WebserverSettings.INTERNAL_IP), port), 10);
|
||||
} else if (server == null) {
|
||||
logger.info("§e" + locale.getString(PluginLang.WEB_SERVER_NOTIFY_USING_PROXY_MODE));
|
||||
server = HttpServer.create(new InetSocketAddress(config.get(WebserverSettings.INTERNAL_IP), port), 10);
|
||||
} else if (config.isTrue(WebserverSettings.DISABLED_AUTHENTICATION)) {
|
||||
logger.info(locale.getString(PluginLang.WEB_SERVER_NOTIFY_HTTPS_USER_AUTH));
|
||||
}
|
||||
server.createContext("/", requestHandler);
|
||||
|
||||
ExecutorService executor = new ThreadPoolExecutor(
|
||||
4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100),
|
||||
new BasicThreadFactory.Builder()
|
||||
.namingPattern("Plan WebServer Thread-%d")
|
||||
.uncaughtExceptionHandler((thread, throwable) -> {
|
||||
if (config.isTrue(PluginSettings.DEV_MODE)) {
|
||||
errorLogger.warn(throwable, ErrorContext.builder()
|
||||
.whatToDo("THIS ERROR IS ONLY LOGGED IN DEV MODE")
|
||||
.build());
|
||||
}
|
||||
}).build()
|
||||
);
|
||||
server.setExecutor(executor);
|
||||
server.start();
|
||||
|
||||
enabled = true;
|
||||
|
||||
String address = addresses.getAccessAddress().orElse(addresses.getFallbackLocalhostAddress());
|
||||
logger.info(locale.getString(PluginLang.ENABLED_WEB_SERVER, server.getAddress().getPort(), address));
|
||||
|
||||
boolean usingAlternativeIP = config.isTrue(WebserverSettings.SHOW_ALTERNATIVE_IP);
|
||||
if (!usingAlternativeIP && addresses.getAccessAddress().isEmpty()) {
|
||||
logger.info("§e" + locale.getString(PluginLang.ENABLE_NOTIFY_EMPTY_IP));
|
||||
}
|
||||
} catch (BindException failedToBind) {
|
||||
logger.error("Webserver failed to bind port: " + failedToBind.toString());
|
||||
enabled = false;
|
||||
} catch (IllegalArgumentException | IllegalStateException | IOException e) {
|
||||
errorLogger.error(e, ErrorContext.builder().related("Trying to enable webserver", config.get(WebserverSettings.INTERNAL_IP) + ":" + port).build());
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean startHttpsServer() throws BindException {
|
||||
String keyStorePath = config.get(WebserverSettings.CERTIFICATE_PATH);
|
||||
|
||||
if ("proxy".equalsIgnoreCase(keyStorePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!Paths.get(keyStorePath).isAbsolute()) {
|
||||
keyStorePath = files.getDataFolder() + File.separator + keyStorePath;
|
||||
}
|
||||
} catch (InvalidPathException e) {
|
||||
logger.error("WebServer: Could not find Keystore: " + e.getMessage());
|
||||
errorLogger.error(e, ErrorContext.builder()
|
||||
.whatToDo(e.getMessage() + ", Fix this path to point to a valid keystore file: " + keyStorePath)
|
||||
.related(keyStorePath).build());
|
||||
}
|
||||
|
||||
char[] storepass = config.get(WebserverSettings.CERTIFICATE_STOREPASS).toCharArray();
|
||||
char[] keypass = config.get(WebserverSettings.CERTIFICATE_KEYPASS).toCharArray();
|
||||
String alias = config.get(WebserverSettings.CERTIFICATE_ALIAS);
|
||||
|
||||
boolean startSuccessful = false;
|
||||
String keyStoreKind = keyStorePath.endsWith(".p12") ? "PKCS12" : "JKS";
|
||||
try (FileInputStream fIn = new FileInputStream(keyStorePath)) {
|
||||
KeyStore keystore = KeyStore.getInstance(keyStoreKind);
|
||||
|
||||
keystore.load(fIn, storepass);
|
||||
Certificate cert = keystore.getCertificate(alias);
|
||||
|
||||
if (cert == null) {
|
||||
throw new IllegalStateException("Alias: '" + alias + "' was not found in file " + keyStorePath + ".");
|
||||
}
|
||||
|
||||
logger.info("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(config.get(WebserverSettings.INTERNAL_IP), 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 (IllegalStateException e) {
|
||||
logger.error(e.getMessage());
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
logger.error(locale.getString(PluginLang.WEB_SERVER_FAIL_SSL_CONTEXT));
|
||||
errorLogger.error(e, ErrorContext.builder().related(keyStoreKind).build());
|
||||
} catch (EOFException e) {
|
||||
logger.error(locale.getString(PluginLang.WEB_SERVER_FAIL_EMPTY_FILE));
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.info(locale.getString(PluginLang.WEB_SERVER_NOTIFY_NO_CERT_FILE, keyStorePath));
|
||||
logger.info(locale.getString(PluginLang.WEB_SERVER_NOTIFY_HTTP));
|
||||
} catch (BindException e) {
|
||||
throw e; // Pass to above error handler
|
||||
} catch (IOException e) {
|
||||
errorLogger.error(e, ErrorContext.builder().related(config.get(WebserverSettings.INTERNAL_IP) + ":" + port).build());
|
||||
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) {
|
||||
logger.error(locale.getString(PluginLang.WEB_SERVER_FAIL_STORE_LOAD));
|
||||
errorLogger.error(e, ErrorContext.builder()
|
||||
.whatToDo("Make sure the Certificate settings are correct / You can try remaking the keystore without -passin or -passout parameters.")
|
||||
.related(keyStorePath).build());
|
||||
}
|
||||
return startSuccessful;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the WebServer is enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the server - Async thread is closed with shutdown boolean.
|
||||
*/
|
||||
@Override
|
||||
public void disable() {
|
||||
if (server != null) {
|
||||
shutdown();
|
||||
logger.info(locale.getString(PluginLang.DISABLED_WEB_SERVER));
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
private void shutdown() {
|
||||
server.stop(0);
|
||||
Executor executor = server.getExecutor();
|
||||
if (executor instanceof ExecutorService) {
|
||||
ExecutorService service = (ExecutorService) executor;
|
||||
service.shutdown();
|
||||
try {
|
||||
if (!service.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||
service.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("WebServer ExecutorService shutdown thread interrupted on disable: " + e.getMessage());
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return usingHttps ? "https" : "http";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsingHTTPS() {
|
||||
return usingHttps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthRequired() {
|
||||
return isUsingHTTPS() && config.isFalse(WebserverSettings.DISABLED_AUTHENTICATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user