From 871fa9b9794789fed1dcc11b4ca2485797e8da8c Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Fri, 22 Feb 2019 10:35:06 +0200 Subject: [PATCH] Added a fail message to web traffic if database is not open --- .../plan/command/commands/InfoCommand.java | 6 +++++- .../java/com/djrapitops/plan/db/Database.java | 2 +- .../main/java/com/djrapitops/plan/db/SQLDB.java | 4 ++-- .../plan/system/webserver/RequestHandler.java | 16 +--------------- .../webserver/auth/BasicAuthentication.java | 5 +++++ .../plan/system/webserver/auth/FailReason.java | 1 + .../webserver/pages/PlayerPageHandler.java | 6 ++++++ .../webserver/pages/PlayersPageHandler.java | 17 +++++++++++++++-- .../webserver/pages/ServerPageHandler.java | 13 ++++++++++++- .../response/PromptAuthorizationResponse.java | 6 +++--- 10 files changed, 51 insertions(+), 25 deletions(-) diff --git a/Plan/common/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java b/Plan/common/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java index 8963b92ac..07adfd4f2 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.command.commands; import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.db.Database; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.connection.ConnectionSystem; import com.djrapitops.plan.system.locale.Locale; @@ -70,12 +71,15 @@ public class InfoCommand extends CommandNode { String updateAvailable = versionCheckSystem.isNewVersionAvailable() ? yes : no; String connectedToBungee = connectionSystem.isServerAvailable() ? yes : no; + + Database database = dbSystem.getDatabase(); + String[] messages = { locale.getString(CommandLang.HEADER_INFO), "", locale.getString(CommandLang.INFO_VERSION, plugin.getVersion()), 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), "", ">" diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/Database.java b/Plan/common/src/main/java/com/djrapitops/plan/db/Database.java index 9057fb23e..b0fb36f7e 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/Database.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/Database.java @@ -71,7 +71,7 @@ public interface Database { enum State { CLOSED, - INITIALIZING, + PATCHING, OPEN } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java b/Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java index ea1dbe848..4db60c1a4 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java @@ -89,7 +89,7 @@ public abstract class SQLDB extends AbstractDatabase { List unfinishedTransactions = closeTransactionExecutor(transactionExecutor); this.transactionExecutor = transactionExecutorServiceProvider.get(); - setState(State.INITIALIZING); + setState(State.PATCHING); setupDataSource(); setupDatabase(); @@ -159,7 +159,7 @@ public abstract class SQLDB extends AbstractDatabase { executeTransaction(new OperationCriticalTransaction() { @Override protected void performOperations() { - if (getState() == State.INITIALIZING) setState(State.OPEN); + if (getState() == State.PATCHING) setState(State.OPEN); } }); registerIndexCreationTask(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java index 65c28e524..74ac1a759 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java @@ -16,7 +16,6 @@ */ package com.djrapitops.plan.system.webserver; -import com.djrapitops.plan.system.DebugChannels; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.locale.Locale; 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.response.PromptAuthorizationResponse; import com.djrapitops.plan.system.webserver.response.Response; -import com.djrapitops.plugin.benchmarking.Benchmark; import com.djrapitops.plugin.benchmarking.Timings; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.console.PluginLogger; @@ -85,14 +83,8 @@ public class RequestHandler implements HttpHandler { Request request = new Request(exchange, locale); request.setAuth(getAuthorization(requestHeaders)); - String requestString = request.toString(); - timings.start(requestString); - int responseCode = -1; - - boolean inDevMode = config.isTrue(PluginSettings.DEV_MODE); try { Response response = responseHandler.getResponse(request); - responseCode = response.getCode(); if (response instanceof PromptAuthorizationResponse) { responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\""); } @@ -100,18 +92,12 @@ public class RequestHandler implements HttpHandler { response.setResponseHeaders(responseHeaders); response.send(exchange, locale, theme); } catch (Exception e) { - if (inDevMode) { + if (config.isTrue(PluginSettings.DEV_MODE)) { logger.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); errorHandler.log(L.WARN, this.getClass(), e); } } finally { exchange.close(); - if (inDevMode) { - logger.getDebugLogger().logOn( - DebugChannels.WEB_REQUESTS, - timings.end(requestString).map(Benchmark::toString).orElse("-") + " Code: " + responseCode - ); - } } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java index b8cf73e1f..4d0fa2019 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java @@ -55,6 +55,11 @@ public class BasicAuthentication implements Authentication { String user = userInfo[0]; 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 { WebUser webUser = database.query(WebUserQueries.fetchWebUser(user)) .orElseThrow(() -> new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, user)); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java index 930ad231c..0a7cfeddf 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java @@ -28,6 +28,7 @@ public enum FailReason implements Lang { USER_AND_PASS_NOT_SPECIFIED("User and Password not specified"), USER_DOES_NOT_EXIST("User does not exist"), 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"); private final String reason; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java index 5cf676efa..e5f10e2f7 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java @@ -17,9 +17,11 @@ package com.djrapitops.plan.system.webserver.pages; 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.WebException; import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.db.Database; import com.djrapitops.plan.db.access.queries.PlayerFetchQueries; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.InfoSystem; @@ -78,6 +80,10 @@ public class PlayerPageHandler implements PageHandler { return responseFactory.uuidNotFound404(); } 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. if (dbSystem.getDatabase().query(PlayerFetchQueries.isPlayerRegistered(uuid))) { if (raw) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java index 3571e138a..64c7acc4c 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java @@ -17,6 +17,10 @@ package com.djrapitops.plan.system.webserver.pages; 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.auth.Authentication; import com.djrapitops.plan.system.webserver.cache.PageId; @@ -36,15 +40,24 @@ import java.util.List; @Singleton public class PlayersPageHandler implements PageHandler { + private final DBSystem dbSystem; private final ResponseFactory responseFactory; @Inject - public PlayersPageHandler(ResponseFactory responseFactory) { + public PlayersPageHandler( + DBSystem dbSystem, + ResponseFactory responseFactory + ) { + this.dbSystem = dbSystem; this.responseFactory = responseFactory; } @Override - public Response getResponse(Request request, List target) { + public Response getResponse(Request request, List 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); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java index 827c2b642..5bc1d0045 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java @@ -18,8 +18,10 @@ package com.djrapitops.plan.system.webserver.pages; import com.djrapitops.plan.api.exceptions.WebUserAuthException; 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.WebException; +import com.djrapitops.plan.db.Database; import com.djrapitops.plan.db.access.queries.objects.ServerQueries; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.InfoSystem; @@ -70,11 +72,12 @@ public class ServerPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) { + public Response getResponse(Request request, List target) throws WebException { UUID serverUUID = getServerUUID(target); boolean raw = target.size() >= 2 && target.get(1).equalsIgnoreCase("raw"); if (raw) { + checkDBState(); return ResponseCache.loadResponse(PageId.RAW_SERVER.of(serverUUID), () -> responseFactory.rawServerPageResponse(serverUUID)); } @@ -83,6 +86,7 @@ public class ServerPageHandler implements PageHandler { if (response != null) { return response; } else { + checkDBState(); if ((Check.isBungeeAvailable() || Check.isVelocityAvailable()) && serverInfo.getServerUUID().equals(serverUUID)) { 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. private Response refreshNow(UUID serverUUID) { processing.submitNonCritical(() -> { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java index 28ac34db2..57a4ce949 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java @@ -45,7 +45,7 @@ public class PromptAuthorizationResponse extends ErrorResponse { public static PromptAuthorizationResponse getBasicAuthResponse(VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException { PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files); 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.replacePlaceholders(); @@ -54,8 +54,6 @@ public class PromptAuthorizationResponse extends ErrorResponse { public static PromptAuthorizationResponse getBasicAuthResponse(WebUserAuthException e, VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException { PromptAuthorizationResponse response = new PromptAuthorizationResponse(versionCheckSystem, files); - response.setHeader("HTTP/1.1 401 Access Denied\r\n" - + "WWW-Authenticate: Basic realm=\"/\";"); FailReason failReason = e.getFailReason(); String reason = failReason.getReason(); @@ -70,6 +68,8 @@ public class PromptAuthorizationResponse extends ErrorResponse { reason += errorBuilder.toString(); } + response.setHeader("HTTP/1.1 401 Access Denied\r\n" + + "WWW-Authenticate: Basic realm=\"" + failReason.getReason() + "\";"); response.setParagraph("Authentication Failed.

Reason: " + reason + "

" + TIPS); response.replacePlaceholders(); return response;