From 45d6bfb8404ff0222e60e6471a3f5dc9046f103b Mon Sep 17 00:00:00 2001
From: Risto Lahtela <24460436+Rsl1122@users.noreply.github.com>
Date: Sat, 28 Mar 2020 13:00:34 +0200
Subject: [PATCH] Made resource resolution more flexible
- API 5.1-R0.2: Added ResolverService#getResolvers method
- /players/ now redirects to /players
- All error pages now have proper css
Affects issues:
- Fixed #1378
---
Plan/api/build.gradle | 2 +-
.../plan/capability/Capability.java | 4 ++
.../plan/delivery/web/ResolverService.java | 13 ++++++
.../plan/delivery/web/ResolverSvc.java | 12 ++++++
.../delivery/webserver/ResponseResolver.java | 40 ++++++++++---------
.../resolver/PlayerPageResolver.java | 27 +++++++++----
.../resolver/PlayersPageResolver.java | 2 +
.../resolver/StaticResourceResolver.java | 12 +++++-
.../settings/locale/lang/ErrorPageLang.java | 2 +-
.../assets/plan/locale/locale_EN.txt | 2 +-
10 files changed, 86 insertions(+), 30 deletions(-)
diff --git a/Plan/api/build.gradle b/Plan/api/build.gradle
index 46ad4aa29..bd0df50bd 100644
--- a/Plan/api/build.gradle
+++ b/Plan/api/build.gradle
@@ -7,7 +7,7 @@ dependencies {
compileOnly "com.google.code.gson:gson:$gsonVersion"
}
-ext.apiVersion = '5.1-R0.1'
+ext.apiVersion = '5.1-R0.2'
bintray {
user = System.getenv('BINTRAY_USER')
diff --git a/Plan/api/src/main/java/com/djrapitops/plan/capability/Capability.java b/Plan/api/src/main/java/com/djrapitops/plan/capability/Capability.java
index 39ec75cd2..b1ac9bf8c 100644
--- a/Plan/api/src/main/java/com/djrapitops/plan/capability/Capability.java
+++ b/Plan/api/src/main/java/com/djrapitops/plan/capability/Capability.java
@@ -67,6 +67,10 @@ enum Capability {
* {@link com.djrapitops.plan.delivery.web.ResolverService}
*/
PAGE_EXTENSION_RESOLVERS,
+ /**
+ * {@link com.djrapitops.plan.delivery.web.ResolverService#getResolvers(String)}
+ */
+ PAGE_EXTENSION_RESOLVERS_LIST,
/**
* {@link com.djrapitops.plan.delivery.web.ResourceService}
*/
diff --git a/Plan/api/src/main/java/com/djrapitops/plan/delivery/web/ResolverService.java b/Plan/api/src/main/java/com/djrapitops/plan/delivery/web/ResolverService.java
index 68d57985c..096c95df3 100644
--- a/Plan/api/src/main/java/com/djrapitops/plan/delivery/web/ResolverService.java
+++ b/Plan/api/src/main/java/com/djrapitops/plan/delivery/web/ResolverService.java
@@ -18,6 +18,7 @@ package com.djrapitops.plan.delivery.web;
import com.djrapitops.plan.delivery.web.resolver.Resolver;
+import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -74,6 +75,18 @@ public interface ResolverService {
*/
Optional getResolver(String target);
+ /**
+ * Obtain all Resolvers that match the target.
+ *
+ * If first returns Optional.empty next one should be used.
+ *
+ * Requires Capability PAGE_EXTENSION_RESOLVERS_LIST.
+ *
+ * @param target "/example/target"
+ * @return List of Resolvers if registered or empty list.
+ */
+ List getResolvers(String target);
+
class Holder {
static ResolverService service;
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java
index f16aec7f8..6c40f3d5c 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java
@@ -68,6 +68,18 @@ public class ResolverSvc implements ResolverService {
return Optional.empty();
}
+ @Override
+ public List getResolvers(String target) {
+ List resolvers = new ArrayList<>();
+ for (Container container : basicResolvers) {
+ if (container.matcher.test(target)) resolvers.add(container.resolver);
+ }
+ for (Container container : regexResolvers) {
+ if (container.matcher.test(target)) resolvers.add(container.resolver);
+ }
+ return resolvers;
+ }
+
public Optional getPluginInChargeOf(String target) {
for (Container container : basicResolvers) {
if (container.matcher.test(target)) return Optional.of(container.plugin);
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java
index 7031b594e..600ba49ff 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java
@@ -35,6 +35,7 @@ import dagger.Lazy;
import javax.inject.Inject;
import javax.inject.Singleton;
+import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -100,7 +101,7 @@ public class ResponseResolver {
resolverService.registerResolver(plugin, "/network", serverPageResolver);
resolverService.registerResolver(plugin, "/server", serverPageResolver);
resolverService.registerResolverForMatches(plugin, Pattern.compile("^/$"), rootPageResolver);
- resolverService.registerResolverForMatches(plugin, Pattern.compile("^/(vendor|css|js|img)/.*"), staticResourceResolver);
+ resolverService.registerResolverForMatches(plugin, Pattern.compile("^.*/(vendor|css|js|img)/.*"), staticResourceResolver);
resolverService.registerResolver(plugin, "/v1", rootJSONResolver.getResolver());
}
@@ -136,30 +137,33 @@ public class ResponseResolver {
Optional authentication = internalRequest.getAuth();
- Optional foundResolver = resolverService.getResolver(internalRequest.getPath().asString());
- if (!foundResolver.isPresent()) return responseFactory.pageNotFound404();
+ List foundResolvers = resolverService.getResolvers(internalRequest.getPath().asString());
+ if (foundResolvers.isEmpty()) return responseFactory.pageNotFound404();
- Resolver resolver = foundResolver.get();
+ for (Resolver resolver : foundResolvers) {
+ Request request = internalRequest.toAPIRequest();
+ if (resolver.requiresAuth(request)) {
+ // Get required auth
+ boolean isAuthRequired = webServer.get().isAuthRequired();
+ if (isAuthRequired && !authentication.isPresent()) {
+ if (webServer.get().isUsingHTTPS()) {
+ return responseFactory.basicAuth();
+ } else {
+ return responseFactory.forbidden403();
+ }
+ }
- Request request = internalRequest.toAPIRequest();
- if (resolver.requiresAuth(request)) {
- // Get required auth
- boolean isAuthRequired = webServer.get().isAuthRequired();
- if (isAuthRequired && !authentication.isPresent()) {
- if (webServer.get().isUsingHTTPS()) {
- return responseFactory.basicAuth();
+ if (!isAuthRequired || resolver.canAccess(request)) {
+ Optional resolved = resolver.resolve(request);
+ if (resolved.isPresent()) return resolved.get();
} else {
return responseFactory.forbidden403();
}
- }
-
- if (!isAuthRequired || resolver.canAccess(request)) {
- return resolver.resolve(request).orElseGet(responseFactory::pageNotFound404);
} else {
- return responseFactory.forbidden403();
+ Optional resolved = resolver.resolve(request);
+ if (resolved.isPresent()) return resolved.get();
}
- } else {
- return resolver.resolve(request).orElseGet(responseFactory::pageNotFound404);
}
+ return responseFactory.pageNotFound404();
}
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java
index 570dd7ed6..949a7cc49 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java
@@ -16,6 +16,7 @@
*/
package com.djrapitops.plan.delivery.webserver.resolver;
+import com.djrapitops.plan.delivery.rendering.html.Html;
import com.djrapitops.plan.delivery.web.resolver.Resolver;
import com.djrapitops.plan.delivery.web.resolver.Response;
import com.djrapitops.plan.delivery.web.resolver.request.Request;
@@ -23,6 +24,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.URIPath;
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
import com.djrapitops.plan.delivery.webserver.ResponseFactory;
import com.djrapitops.plan.identification.UUIDUtility;
+import org.apache.commons.lang3.StringUtils;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -60,17 +62,26 @@ public class PlayerPageResolver implements Resolver {
@Override
public Optional resolve(Request request) {
URIPath path = request.getPath();
- Optional part = path.getPart(1);
- if (!part.isPresent()) return Optional.empty();
+ if (StringUtils.containsAny(path.asString(), "/vendor/", "/js/", "/css/", "/img/")) {
+ return Optional.empty();
+ }
+ return path.getPart(1)
+ .map(playerName -> getResponse(request.getPath(), playerName));
+ }
- String playerName = part.get();
+ private Response getResponse(URIPath path, String playerName) {
UUID playerUUID = uuidUtility.getUUIDOf(playerName);
- if (playerUUID == null) return Optional.of(responseFactory.uuidNotFound404());
+ if (playerUUID == null) return responseFactory.uuidNotFound404();
boolean raw = path.getPart(2).map("raw"::equalsIgnoreCase).orElse(false);
- return Optional.of(
- raw ? responseFactory.rawPlayerPageResponse(playerUUID)
- : responseFactory.playerPageResponse(playerUUID)
- );
+ if (raw) {
+ return responseFactory.rawPlayerPageResponse(playerUUID);
+ }
+
+ if (path.getPart(2).isPresent()) {
+ // Redirect /player/Name/ to /player/Name
+ return responseFactory.redirectResponse("../" + Html.encodeToURL(playerName));
+ }
+ return responseFactory.playerPageResponse(playerUUID);
}
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayersPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayersPageResolver.java
index 07309136b..d9e10b9c3 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayersPageResolver.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayersPageResolver.java
@@ -49,6 +49,8 @@ public class PlayersPageResolver implements Resolver {
@Override
public Optional resolve(Request request) {
+ // Redirect /players/ to /players
+ if (request.getPath().getPart(1).isPresent()) return Optional.of(responseFactory.redirectResponse("/players"));
return Optional.of(responseFactory.playersPageResponse());
}
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java
index 3b2786575..6c0d1867f 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java
@@ -19,6 +19,7 @@ package com.djrapitops.plan.delivery.webserver.resolver;
import com.djrapitops.plan.delivery.web.resolver.NoAuthResolver;
import com.djrapitops.plan.delivery.web.resolver.Response;
import com.djrapitops.plan.delivery.web.resolver.request.Request;
+import com.djrapitops.plan.delivery.web.resolver.request.URIPath;
import com.djrapitops.plan.delivery.webserver.ResponseFactory;
import org.apache.commons.lang3.StringUtils;
@@ -47,7 +48,7 @@ public class StaticResourceResolver implements NoAuthResolver {
}
private Response getResponse(Request request) {
- String resource = request.getPath().asString().substring(1);
+ String resource = getPath(request).asString().substring(1);
if (resource.endsWith(".css")) {
return responseFactory.cssResponse(resource);
}
@@ -62,4 +63,13 @@ public class StaticResourceResolver implements NoAuthResolver {
}
return null;
}
+
+ private URIPath getPath(Request request) {
+ URIPath path = request.getPath();
+ // Remove everything before /vendor /css /js or /img
+ while (!path.getPart(0).map(part -> part.matches("(vendor|css|js|img)")).orElse(true)) {
+ path = path.omitFirst();
+ }
+ return path;
+ }
}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/ErrorPageLang.java b/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/ErrorPageLang.java
index 4c0b3e180..8091a1c36 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/ErrorPageLang.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/ErrorPageLang.java
@@ -24,7 +24,7 @@ package com.djrapitops.plan.settings.locale.lang;
public enum ErrorPageLang implements Lang {
UUID_404("Player UUID was not found in the database."),
NO_SERVERS_404("No Servers online to perform the request."),
- NOT_PLAYED_404("Player has not played on this server."),
+ NOT_PLAYED_404("Plan has not seen this player."),
UNKNOWN_PAGE_404("Make sure you're accessing a link given by a command, Examples:
/player/PlayerName
/server/ServerName
"),
UNAUTHORIZED_401("Unauthorized"),
AUTHENTICATION_FAILED_401("Authentication Failed."),
diff --git a/Plan/common/src/main/resources/assets/plan/locale/locale_EN.txt b/Plan/common/src/main/resources/assets/plan/locale/locale_EN.txt
index 0d9d56df7..53d2e10eb 100644
--- a/Plan/common/src/main/resources/assets/plan/locale/locale_EN.txt
+++ b/Plan/common/src/main/resources/assets/plan/locale/locale_EN.txt
@@ -295,7 +295,7 @@ HTML ERRORS - AUTHENTICATION_FAILED_401 || Authentication Failed.
HTML ERRORS - FORBIDDEN_403 || Forbidden
HTML ERRORS - NO_SERVERS_404 || No Servers online to perform the request.
HTML ERRORS - NOT_FOUND_404 || Not Found
-HTML ERRORS - NOT_PLAYED_404 || Player has not played on this server.
+HTML ERRORS - NOT_PLAYED_404 || Plan has not seen this player.
HTML ERRORS - PAGE_NOT_FOUND_404 || Page does not exist.
HTML ERRORS - UNAUTHORIZED_401 || Unauthorized
HTML ERRORS - UNKNOWN_PAGE_404 || Make sure you're accessing a link given by a command, Examples:
/player/PlayerName
/server/ServerName