Added a fail message to web traffic if database is not open

This commit is contained in:
Rsl1122 2019-02-22 10:35:06 +02:00
parent ac7093237e
commit 871fa9b979
10 changed files with 51 additions and 25 deletions

View File

@ -17,6 +17,7 @@
package com.djrapitops.plan.command.commands; package com.djrapitops.plan.command.commands;
import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.connection.ConnectionSystem; import com.djrapitops.plan.system.info.connection.ConnectionSystem;
import com.djrapitops.plan.system.locale.Locale; import com.djrapitops.plan.system.locale.Locale;
@ -70,12 +71,15 @@ public class InfoCommand extends CommandNode {
String updateAvailable = versionCheckSystem.isNewVersionAvailable() ? yes : no; String updateAvailable = versionCheckSystem.isNewVersionAvailable() ? yes : no;
String connectedToBungee = connectionSystem.isServerAvailable() ? yes : no; String connectedToBungee = connectionSystem.isServerAvailable() ? yes : no;
Database database = dbSystem.getDatabase();
String[] messages = { String[] messages = {
locale.getString(CommandLang.HEADER_INFO), locale.getString(CommandLang.HEADER_INFO),
"", "",
locale.getString(CommandLang.INFO_VERSION, plugin.getVersion()), locale.getString(CommandLang.INFO_VERSION, plugin.getVersion()),
locale.getString(CommandLang.INFO_UPDATE, updateAvailable), locale.getString(CommandLang.INFO_UPDATE, updateAvailable),
locale.getString(CommandLang.INFO_DATABASE, dbSystem.getDatabase().getType().getName()), locale.getString(CommandLang.INFO_DATABASE, database.getType().getName() + " (" + database.getState().name() + ")"),
locale.getString(CommandLang.INFO_BUNGEE_CONNECTION, connectedToBungee), locale.getString(CommandLang.INFO_BUNGEE_CONNECTION, connectedToBungee),
"", "",
">" ">"

View File

@ -71,7 +71,7 @@ public interface Database {
enum State { enum State {
CLOSED, CLOSED,
INITIALIZING, PATCHING,
OPEN OPEN
} }
} }

View File

@ -89,7 +89,7 @@ public abstract class SQLDB extends AbstractDatabase {
List<Runnable> unfinishedTransactions = closeTransactionExecutor(transactionExecutor); List<Runnable> unfinishedTransactions = closeTransactionExecutor(transactionExecutor);
this.transactionExecutor = transactionExecutorServiceProvider.get(); this.transactionExecutor = transactionExecutorServiceProvider.get();
setState(State.INITIALIZING); setState(State.PATCHING);
setupDataSource(); setupDataSource();
setupDatabase(); setupDatabase();
@ -159,7 +159,7 @@ public abstract class SQLDB extends AbstractDatabase {
executeTransaction(new OperationCriticalTransaction() { executeTransaction(new OperationCriticalTransaction() {
@Override @Override
protected void performOperations() { protected void performOperations() {
if (getState() == State.INITIALIZING) setState(State.OPEN); if (getState() == State.PATCHING) setState(State.OPEN);
} }
}); });
registerIndexCreationTask(); registerIndexCreationTask();

View File

@ -16,7 +16,6 @@
*/ */
package com.djrapitops.plan.system.webserver; package com.djrapitops.plan.system.webserver;
import com.djrapitops.plan.system.DebugChannels;
import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.locale.Locale; import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.settings.config.PlanConfig; import com.djrapitops.plan.system.settings.config.PlanConfig;
@ -26,7 +25,6 @@ import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.auth.BasicAuthentication; import com.djrapitops.plan.system.webserver.auth.BasicAuthentication;
import com.djrapitops.plan.system.webserver.response.PromptAuthorizationResponse; import com.djrapitops.plan.system.webserver.response.PromptAuthorizationResponse;
import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plugin.benchmarking.Benchmark;
import com.djrapitops.plugin.benchmarking.Timings; import com.djrapitops.plugin.benchmarking.Timings;
import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.L;
import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.console.PluginLogger;
@ -85,14 +83,8 @@ public class RequestHandler implements HttpHandler {
Request request = new Request(exchange, locale); Request request = new Request(exchange, locale);
request.setAuth(getAuthorization(requestHeaders)); request.setAuth(getAuthorization(requestHeaders));
String requestString = request.toString();
timings.start(requestString);
int responseCode = -1;
boolean inDevMode = config.isTrue(PluginSettings.DEV_MODE);
try { try {
Response response = responseHandler.getResponse(request); Response response = responseHandler.getResponse(request);
responseCode = response.getCode();
if (response instanceof PromptAuthorizationResponse) { if (response instanceof PromptAuthorizationResponse) {
responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\""); responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\"");
} }
@ -100,18 +92,12 @@ public class RequestHandler implements HttpHandler {
response.setResponseHeaders(responseHeaders); response.setResponseHeaders(responseHeaders);
response.send(exchange, locale, theme); response.send(exchange, locale, theme);
} catch (Exception e) { } catch (Exception e) {
if (inDevMode) { if (config.isTrue(PluginSettings.DEV_MODE)) {
logger.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); logger.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:");
errorHandler.log(L.WARN, this.getClass(), e); errorHandler.log(L.WARN, this.getClass(), e);
} }
} finally { } finally {
exchange.close(); exchange.close();
if (inDevMode) {
logger.getDebugLogger().logOn(
DebugChannels.WEB_REQUESTS,
timings.end(requestString).map(Benchmark::toString).orElse("-") + " Code: " + responseCode
);
}
} }
} }

View File

@ -55,6 +55,11 @@ public class BasicAuthentication implements Authentication {
String user = userInfo[0]; String user = userInfo[0];
String passwordRaw = userInfo[1]; String passwordRaw = userInfo[1];
Database.State dbState = database.getState();
if (dbState != Database.State.OPEN) {
throw new WebUserAuthException(FailReason.DATABASE_NOT_OPEN, "State was: " + dbState.name());
}
try { try {
WebUser webUser = database.query(WebUserQueries.fetchWebUser(user)) WebUser webUser = database.query(WebUserQueries.fetchWebUser(user))
.orElseThrow(() -> new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, user)); .orElseThrow(() -> new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, user));

View File

@ -28,6 +28,7 @@ public enum FailReason implements Lang {
USER_AND_PASS_NOT_SPECIFIED("User and Password not specified"), USER_AND_PASS_NOT_SPECIFIED("User and Password not specified"),
USER_DOES_NOT_EXIST("User does not exist"), USER_DOES_NOT_EXIST("User does not exist"),
USER_PASS_MISMATCH("User and Password did not match"), USER_PASS_MISMATCH("User and Password did not match"),
DATABASE_NOT_OPEN("Database is not open, check db status with /plan info"),
ERROR("Authentication failed due to error"); ERROR("Authentication failed due to error");
private final String reason; private final String reason;

View File

@ -17,9 +17,11 @@
package com.djrapitops.plan.system.webserver.pages; package com.djrapitops.plan.system.webserver.pages;
import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.ForbiddenException;
import com.djrapitops.plan.api.exceptions.connection.NoServersException; import com.djrapitops.plan.api.exceptions.connection.NoServersException;
import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.data.WebUser;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries; import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.InfoSystem; import com.djrapitops.plan.system.info.InfoSystem;
@ -78,6 +80,10 @@ public class PlayerPageHandler implements PageHandler {
return responseFactory.uuidNotFound404(); return responseFactory.uuidNotFound404();
} }
try { try {
Database.State dbState = dbSystem.getDatabase().getState();
if (dbState != Database.State.OPEN) {
throw new ForbiddenException("Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info");
}
// TODO Move this Database dependency to PlayerPage generation in PageFactory instead. // TODO Move this Database dependency to PlayerPage generation in PageFactory instead.
if (dbSystem.getDatabase().query(PlayerFetchQueries.isPlayerRegistered(uuid))) { if (dbSystem.getDatabase().query(PlayerFetchQueries.isPlayerRegistered(uuid))) {
if (raw) { if (raw) {

View File

@ -17,6 +17,10 @@
package com.djrapitops.plan.system.webserver.pages; package com.djrapitops.plan.system.webserver.pages;
import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.ForbiddenException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.webserver.Request; import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.cache.PageId; import com.djrapitops.plan.system.webserver.cache.PageId;
@ -36,15 +40,24 @@ import java.util.List;
@Singleton @Singleton
public class PlayersPageHandler implements PageHandler { public class PlayersPageHandler implements PageHandler {
private final DBSystem dbSystem;
private final ResponseFactory responseFactory; private final ResponseFactory responseFactory;
@Inject @Inject
public PlayersPageHandler(ResponseFactory responseFactory) { public PlayersPageHandler(
DBSystem dbSystem,
ResponseFactory responseFactory
) {
this.dbSystem = dbSystem;
this.responseFactory = responseFactory; this.responseFactory = responseFactory;
} }
@Override @Override
public Response getResponse(Request request, List<String> target) { public Response getResponse(Request request, List<String> target) throws WebException {
Database.State dbState = dbSystem.getDatabase().getState();
if (dbState != Database.State.OPEN) {
throw new ForbiddenException("Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info");
}
return ResponseCache.loadResponse(PageId.PLAYERS.id(), responseFactory::playersPageResponse); return ResponseCache.loadResponse(PageId.PLAYERS.id(), responseFactory::playersPageResponse);
} }

View File

@ -18,8 +18,10 @@ package com.djrapitops.plan.system.webserver.pages;
import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException; import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException;
import com.djrapitops.plan.api.exceptions.connection.ForbiddenException;
import com.djrapitops.plan.api.exceptions.connection.NoServersException; import com.djrapitops.plan.api.exceptions.connection.NoServersException;
import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.objects.ServerQueries; import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.InfoSystem; import com.djrapitops.plan.system.info.InfoSystem;
@ -70,11 +72,12 @@ public class ServerPageHandler implements PageHandler {
} }
@Override @Override
public Response getResponse(Request request, List<String> target) { public Response getResponse(Request request, List<String> target) throws WebException {
UUID serverUUID = getServerUUID(target); UUID serverUUID = getServerUUID(target);
boolean raw = target.size() >= 2 && target.get(1).equalsIgnoreCase("raw"); boolean raw = target.size() >= 2 && target.get(1).equalsIgnoreCase("raw");
if (raw) { if (raw) {
checkDBState();
return ResponseCache.loadResponse(PageId.RAW_SERVER.of(serverUUID), () -> responseFactory.rawServerPageResponse(serverUUID)); return ResponseCache.loadResponse(PageId.RAW_SERVER.of(serverUUID), () -> responseFactory.rawServerPageResponse(serverUUID));
} }
@ -83,6 +86,7 @@ public class ServerPageHandler implements PageHandler {
if (response != null) { if (response != null) {
return response; return response;
} else { } else {
checkDBState();
if ((Check.isBungeeAvailable() || Check.isVelocityAvailable()) && serverInfo.getServerUUID().equals(serverUUID)) { if ((Check.isBungeeAvailable() || Check.isVelocityAvailable()) && serverInfo.getServerUUID().equals(serverUUID)) {
return ResponseCache.loadResponse(PageId.SERVER.of(serverUUID), responseFactory::networkPageResponse); return ResponseCache.loadResponse(PageId.SERVER.of(serverUUID), responseFactory::networkPageResponse);
} }
@ -90,6 +94,13 @@ public class ServerPageHandler implements PageHandler {
} }
} }
private void checkDBState() throws ForbiddenException {
Database.State dbState = dbSystem.getDatabase().getState();
if (dbState != Database.State.OPEN) {
throw new ForbiddenException("Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info");
}
}
// TODO Split responsibility so that this method does not call system to refresh and also render a refresh page. // TODO Split responsibility so that this method does not call system to refresh and also render a refresh page.
private Response refreshNow(UUID serverUUID) { private Response refreshNow(UUID serverUUID) {
processing.submitNonCritical(() -> { processing.submitNonCritical(() -> {

View File

@ -45,7 +45,7 @@ public class PromptAuthorizationResponse extends ErrorResponse {
public static PromptAuthorizationResponse getBasicAuthResponse(VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException { public static PromptAuthorizationResponse getBasicAuthResponse(VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException {
PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files); PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files);
response.setHeader("HTTP/1.1 401 Access Denied\r\n" response.setHeader("HTTP/1.1 401 Access Denied\r\n"
+ "WWW-Authenticate: Basic realm=\"/\";"); + "WWW-Authenticate: Basic realm=\"Plan WebUser (/plan register)\";");
response.setParagraph("Authentication Failed." + TIPS); response.setParagraph("Authentication Failed." + TIPS);
response.replacePlaceholders(); response.replacePlaceholders();
@ -54,8 +54,6 @@ public class PromptAuthorizationResponse extends ErrorResponse {
public static PromptAuthorizationResponse getBasicAuthResponse(WebUserAuthException e, VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException { public static PromptAuthorizationResponse getBasicAuthResponse(WebUserAuthException e, VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException {
PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files); PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files);
response.setHeader("HTTP/1.1 401 Access Denied\r\n"
+ "WWW-Authenticate: Basic realm=\"/\";");
FailReason failReason = e.getFailReason(); FailReason failReason = e.getFailReason();
String reason = failReason.getReason(); String reason = failReason.getReason();
@ -70,6 +68,8 @@ public class PromptAuthorizationResponse extends ErrorResponse {
reason += errorBuilder.toString(); reason += errorBuilder.toString();
} }
response.setHeader("HTTP/1.1 401 Access Denied\r\n"
+ "WWW-Authenticate: Basic realm=\"" + failReason.getReason() + "\";");
response.setParagraph("Authentication Failed.</p><p><b>Reason: " + reason + "</b></p><p>" + TIPS); response.setParagraph("Authentication Failed.</p><p><b>Reason: " + reason + "</b></p><p>" + TIPS);
response.replacePlaceholders(); response.replacePlaceholders();
return response; return response;