mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-30 13:08:00 +01:00
parent
62f3f46678
commit
e7da714f55
@ -4,6 +4,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compileOnly group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'
|
||||
compileOnly "com.google.code.gson:gson:$gsonVersion"
|
||||
}
|
||||
|
||||
ext.apiVersion = '5.0-R0.3'
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.web;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.resolver.Resolver;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Service for modifying webserver request resolution.
|
||||
* <p>
|
||||
* It is recommended to use plugin based namespace in your custom targets,
|
||||
* eg. "/flyplugin/flying" to avoid collisions with other plugins.
|
||||
* You can also use {@link #getResolver(String)} to check if target is already resolved.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface ResolverService {
|
||||
|
||||
/**
|
||||
* Register a new resolver.
|
||||
*
|
||||
* @param pluginName Name of the plugin that is registering (For error messages)
|
||||
* @param start Start of the target to match against, eg "/example" will send "/example/target" etc to the Resolver.
|
||||
* @param resolver {@link Resolver} to use for this
|
||||
* @throws IllegalArgumentException If pluginName is null or empty.
|
||||
*/
|
||||
void registerResolver(String pluginName, String start, Resolver resolver);
|
||||
|
||||
/**
|
||||
* Register a new resolver with regex that maches start of target.
|
||||
* <p>
|
||||
* NOTICE: It is recommended to avoid too generic regex like "/.*" to not override existing resolvers.
|
||||
* <p>
|
||||
* Parameters (?param=value) are not included in the regex matching.
|
||||
*
|
||||
* @param pluginName Name of the plugin that is registering (For error messages)
|
||||
* @param pattern Regex Pattern, "/example.*" will send "/exampletarget" etc to the Resolver.
|
||||
* @param resolver {@link Resolver} to use for this.
|
||||
* @throws IllegalArgumentException If pluginName is null or empty.
|
||||
*/
|
||||
void registerResolverForMatches(String pluginName, Pattern pattern, Resolver resolver);
|
||||
|
||||
/**
|
||||
* Obtain a {@link Resolver} for a target.
|
||||
* <p>
|
||||
* First matching resolver will be returned.
|
||||
* {@link #registerResolver} resolvers have higher priority than {@link #registerResolverForMatches}.
|
||||
* <p>
|
||||
* Can be used when making Resolver middleware.
|
||||
*
|
||||
* @param target "/example/target"
|
||||
* @return Resolver if registered or empty.
|
||||
*/
|
||||
Optional<Resolver> getResolver(String target);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
public final class MimeType {
|
||||
public static final String HTML = "text/html";
|
||||
public static final String CSS = "text/css";
|
||||
public static final String JSON = "application/json";
|
||||
public static final String JS = "application/javascript";
|
||||
public static final String IMAGE = "image/gif";
|
||||
public static final String FAVICON = "image/x-icon";
|
||||
public static final String FONT_TFF = "application/x-font-ttf";
|
||||
public static final String FONT_WOFF = "application/font-woff";
|
||||
public static final String FONT_WOFF2 = "application/font-woff2";
|
||||
public static final String FONT_EOT = "application/vnd.ms-fontobject";
|
||||
public static final String FONT_BYTESTREAM = "application/octet-stream";
|
||||
|
||||
private MimeType() {
|
||||
// Static variable class
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents URI parameters described with {@code ?param=value¶m2=value2} in the URL.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public final class Parameters {
|
||||
|
||||
private final Map<String, String> byKey;
|
||||
|
||||
public Parameters(Map<String, String> byKey) {
|
||||
this.byKey = byKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain an URI parameter by key.
|
||||
*
|
||||
* @param key Case-sensitive key, eg. 'param' in {@code ?param=value¶m2=value2}
|
||||
* @return The value in the URL or empty if key is not specified in the URL.
|
||||
*/
|
||||
public Optional<String> get(String key) {
|
||||
return Optional.ofNullable(byKey.get(key));
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Resolver {
|
||||
|
||||
/**
|
||||
* Implement access control if authorization is enabled.
|
||||
* <p>
|
||||
* Is not called when access control is not active.
|
||||
*
|
||||
* @param permissions WebUser that is accessing this page.
|
||||
* @param target Target that is being accessed, /example/target
|
||||
* @param parameters Parameters in the URL, ?param=value etc.
|
||||
* @return true if allowed, false if response should be 403 (forbidden)
|
||||
*/
|
||||
boolean canAccess(WebUser permissions, URLTarget target, Parameters parameters);
|
||||
|
||||
/**
|
||||
* Implement request resolution.
|
||||
*
|
||||
* @param target Target that is being accessed, /example/target
|
||||
* @param parameters Parameters in the URL, ?param=value etc.
|
||||
* @return Response or empty if the response should be 404 (not found).
|
||||
* @see Response for return value
|
||||
*/
|
||||
Optional<Response> resolve(URLTarget target, Parameters parameters);
|
||||
|
||||
default ResponseBuilder newResponseBuilder() {
|
||||
return new ResponseBuilder();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a response that will be sent over HTTP.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see MimeType for MIME types that are commonly used.
|
||||
*/
|
||||
public final class Response {
|
||||
|
||||
final Map<String, String> headers;
|
||||
int code = 200;
|
||||
byte[] bytes;
|
||||
Charset charset; // can be null (raw bytes)
|
||||
|
||||
Response() {
|
||||
headers = new HashMap<>();
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public Optional<Charset> getCharset() {
|
||||
return Optional.ofNullable(charset);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ResponseBuilder {
|
||||
|
||||
private final Response response;
|
||||
|
||||
ResponseBuilder() {
|
||||
this.response = new Response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MIME Type of the Response.
|
||||
*
|
||||
* @param mimeType MIME type of the Response https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
|
||||
* @return this builder.
|
||||
* @see MimeType for common MIME types.
|
||||
*/
|
||||
public ResponseBuilder setMimeType(String mimeType) {
|
||||
return setHeader("Content-Type", mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP Status code.
|
||||
* <p>
|
||||
* Default status code is 200 (OK) if not set.
|
||||
*
|
||||
* @param code 1xx, 2xx, 3xx, 4xx, 5xx, https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
||||
* @return this builder.
|
||||
*/
|
||||
public ResponseBuilder setStatus(int code) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP Response header.
|
||||
*
|
||||
* @param header Key of the header. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
|
||||
* @param value Value for the header.
|
||||
* @return this builder.
|
||||
*/
|
||||
public ResponseBuilder setHeader(String header, Object value) {
|
||||
response.headers.put(header, value.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for building redirects.
|
||||
*
|
||||
* @param url URL to redirect the client to with 302 Found.
|
||||
* @return https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location
|
||||
*/
|
||||
public ResponseBuilder redirectTo(String url) {
|
||||
return setStatus(302).setHeader("Location", url).setContent(new byte[]{});
|
||||
}
|
||||
|
||||
public ResponseBuilder setContent(byte[] bytes) {
|
||||
response.bytes = bytes;
|
||||
return setHeader("Content-Length", bytes.length);
|
||||
}
|
||||
|
||||
public ResponseBuilder setContent(String utf8String) {
|
||||
return setContent(utf8String, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public ResponseBuilder setContent(String content, Charset charset) {
|
||||
String mimeType = response.headers.get("Content-Type");
|
||||
response.charset = charset;
|
||||
|
||||
if (mimeType != null) {
|
||||
String[] parts = mimeType.split(";");
|
||||
if (parts.length == 1) {
|
||||
setMimeType(parts[0] + "; charset=" + charset.name().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
return setContent(content.getBytes(charset));
|
||||
}
|
||||
|
||||
public ResponseBuilder setJSONContent(Object objectToSerialize) {
|
||||
return setJSONContent(new Gson().toJson(objectToSerialize));
|
||||
}
|
||||
|
||||
public ResponseBuilder setJSONContent(String json) {
|
||||
setContent(json);
|
||||
return setMimeType(MimeType.JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish building.
|
||||
*
|
||||
* @return Response.
|
||||
* @throws InvalidResponseException if content was not defined (not even empty byte array).
|
||||
* @throws InvalidResponseException if content has bytes, but MIME-type is not defined.
|
||||
* @throws InvalidResponseException if status code is outside range 100-599.
|
||||
* @see #setMimeType(String) to set MIME-type.
|
||||
*/
|
||||
public Response build() {
|
||||
byte[] content = response.bytes;
|
||||
exceptionIf(content == null, "Content not defined for Response");
|
||||
String mimeType = response.getHeaders().get("Content-Type");
|
||||
exceptionIf(content.length > 0 && mimeType == null, "MIME Type not defined for Response");
|
||||
exceptionIf(content.length > 0 && mimeType.isEmpty(), "MIME Type empty for Response");
|
||||
exceptionIf(response.code < 100 || response.code >= 600, "HTTP Status code out of bounds (" + response.code + ")");
|
||||
return response;
|
||||
}
|
||||
|
||||
private void exceptionIf(boolean value, String errorMsg) {
|
||||
if (value) throw new InvalidResponseException(errorMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when {@link ResponseBuilder} is missing some parameters.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public static class InvalidResponseException extends IllegalStateException {
|
||||
public InvalidResponseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class URLTarget {
|
||||
|
||||
// Internal representation
|
||||
private final List<String> parts;
|
||||
private final String full;
|
||||
|
||||
public URLTarget(String target) {
|
||||
this.parts = parse(target);
|
||||
full = target;
|
||||
}
|
||||
|
||||
private List<String> parse(String target) {
|
||||
String[] partArray = target.split("/");
|
||||
// Ignores index 0, assuming target starts with /
|
||||
return Arrays.asList(partArray)
|
||||
.subList(1, partArray.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the full target.
|
||||
*
|
||||
* @return Example: "/target/path/in/url"
|
||||
*/
|
||||
public String asString() {
|
||||
return full;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain part of the target by index of slashes in the URL.
|
||||
*
|
||||
* @param index Index from root, eg. /0/1/2/3 etc
|
||||
* @return part after a '/' in the target, Example "target" for 0 in "/target/example", "" for 0 in "/", "" for 1 in "/example/"
|
||||
*/
|
||||
public Optional<String> getPart(int index) {
|
||||
if (index >= parts.size()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(parts.get(index));
|
||||
}
|
||||
|
||||
public boolean endsWith(String suffix) {
|
||||
return full.endsWith(suffix);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.web.resolver;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class WebUser {
|
||||
|
||||
private final String name;
|
||||
private final Set<String> permissions;
|
||||
|
||||
public WebUser(String name) {
|
||||
this.name = name;
|
||||
this.permissions = new HashSet<>();
|
||||
}
|
||||
|
||||
public WebUser(String name, String... permissions) {
|
||||
this(name);
|
||||
this.permissions.addAll(Arrays.asList(permissions));
|
||||
}
|
||||
|
||||
public boolean hasPermission(String permission) {
|
||||
return permissions.contains(permission);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user