implemented working WhitelistRepository

This commit is contained in:
Elias Müller 2024-12-05 12:46:51 +01:00
parent b3c43f1763
commit 8811328571
12 changed files with 118 additions and 83 deletions

View File

@ -20,7 +20,7 @@ public final class Main extends JavaPlugin {
private static Logger logger; private static Logger logger;
private List<Appliance> appliances; private List<Appliance> appliances;
private final RepositoryLoader repositoryLoader = new RepositoryLoader(); private RepositoryLoader repositoryLoader;
@Override @Override
public void onEnable() { public void onEnable() {
@ -39,7 +39,11 @@ public final class Main extends JavaPlugin {
Configuration.readConfig(); Configuration.readConfig();
List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances"); List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances");
Main.logger.info("Loading appliances..."); Main.logger().info("Loading Repositories...");
this.repositoryLoader = new RepositoryLoader();
Main.logger().info(String.format("Loaded %d repositories!", this.repositoryLoader.getRepositories().size()));
Main.logger().info("Loading appliances...");
Reflections reflections = new Reflections(this.getClass().getPackageName()); Reflections reflections = new Reflections(this.getClass().getPackageName());
Set<Class<? extends Appliance>> applianceClasses = reflections.getSubTypesOf(Appliance.class); Set<Class<? extends Appliance>> applianceClasses = reflections.getSubTypesOf(Appliance.class);

View File

@ -12,7 +12,8 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.function.Consumer; import java.util.function.Consumer;
public class HttpRepository extends Repository { @RepositoryLoader.IgnoreRepository
public abstract class HttpRepository extends Repository {
private final Consumer<URIBuilder> baseUriBuilder; private final Consumer<URIBuilder> baseUriBuilder;
public HttpRepository(URI basePath) { public HttpRepository(URI basePath) {
@ -26,29 +27,26 @@ public class HttpRepository extends Repository {
: baseUriBuilder; : baseUriBuilder;
} }
public record RequestResponse<TData>(int status, TData data) { protected <TInput, TOutput> ReqResp<TOutput> post(String command, TInput data, Class<TOutput> outputType) {
return this.post(command, parameters -> {}, data, outputType);
} }
protected <TInput, TOutput> ReqResp<TOutput> post(String command, Consumer<URIBuilder> parameters, TInput data, Class<TOutput> outputType) {
protected <TInput, TOutput> RequestResponse<TOutput> post(String command, TInput data, Class<TOutput> clazz) {
return this.post(command, parameters -> {}, data, clazz);
}
protected <TInput, TOutput> RequestResponse<TOutput> post(String command, Consumer<URIBuilder> parameters, TInput data, Class<TOutput> clazz) {
HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters)) HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters))
.POST(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data))) .POST(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data)))
.build(); .build();
return this.execute(request, clazz); return this.execute(request, outputType);
} }
protected <TOutput> RequestResponse<TOutput> get(String command, Class<TOutput> clazz) { protected <TOutput> ReqResp<TOutput> get(String command, Class<TOutput> outputType) {
return this.get(command, parameters -> {}, clazz); return this.get(command, parameters -> {}, outputType);
} }
protected <TOutput> RequestResponse<TOutput> get(String command, Consumer<URIBuilder> parameters, Class<TOutput> clazz) { protected <TOutput> ReqResp<TOutput> get(String command, Consumer<URIBuilder> parameters, Class<TOutput> outputType) {
HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters)) HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters))
.GET() .GET()
.build(); .build();
return this.execute(request, clazz); return this.execute(request, outputType);
} }
private URI getUri(String command, Consumer<URIBuilder> parameters) { private URI getUri(String command, Consumer<URIBuilder> parameters) {
@ -69,15 +67,15 @@ public class HttpRepository extends Repository {
.header("Content-Type", "application/json"); .header("Content-Type", "application/json");
} }
private <TResponse> RequestResponse<TResponse> execute(HttpRequest request, Class<TResponse> clazz) { private <TResponse> ReqResp<TResponse> execute(HttpRequest request, Class<TResponse> clazz) {
RequestResponse<String> rawResponse = this.sendHttp(request); ReqResp<String> rawResponse = this.sendHttp(request);
return new RequestResponse<>(rawResponse.status, this.gson.fromJson(rawResponse.data, clazz)); return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz));
} }
private RequestResponse<String> sendHttp(HttpRequest request) { private ReqResp<String> sendHttp(HttpRequest request) {
try(HttpClient client = HttpClient.newHttpClient()) { try(HttpClient client = HttpClient.newHttpClient()) {
HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
return new RequestResponse<>(httpResponse.statusCode(), httpResponse.body()); return new ReqResp<>(httpResponse.statusCode(), httpResponse.body());
} catch(IOException | InterruptedException e) { } catch(IOException | InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -4,7 +4,7 @@ import com.google.gson.Gson;
import java.net.URI; import java.net.URI;
public class Repository { public abstract class Repository {
protected URI basePath; protected URI basePath;
protected Gson gson; protected Gson gson;

View File

@ -3,6 +3,8 @@ package eu.mhsl.craftattack.spawn.api.client;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import org.reflections.Reflections; import org.reflections.Reflections;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -10,14 +12,19 @@ import java.util.Set;
public class RepositoryLoader { public class RepositoryLoader {
private final List<Repository> repositories; private final List<Repository> repositories;
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreRepository {
}
public RepositoryLoader() { public RepositoryLoader() {
Reflections reflections = new Reflections(this.getClass().getPackageName()); Reflections reflections = new Reflections(this.getClass().getPackageName());
Set<Class<? extends Repository>> repositories = reflections.getSubTypesOf(Repository.class); Set<Class<? extends Repository>> repositories = reflections.getSubTypesOf(Repository.class);
this.repositories = repositories.stream() this.repositories = repositories.stream()
.map(clazz -> { .filter(repository -> !repository.isAnnotationPresent(IgnoreRepository.class))
.map(repository -> {
try { try {
return (Repository) clazz.getDeclaredConstructor().newInstance(); return (Repository) repository.getDeclaredConstructor().newInstance();
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { } catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -33,4 +40,8 @@ public class RepositoryLoader {
.findFirst() .findFirst()
.orElseThrow(() -> new NotImplementedException(String.format("Repository '%s' not found!", clazz.getSimpleName()))); .orElseThrow(() -> new NotImplementedException(String.format("Repository '%s' not found!", clazz.getSimpleName())));
} }
public List<Repository> getRepositories() {
return repositories;
}
} }

View File

@ -0,0 +1,4 @@
package eu.mhsl.craftattack.spawn.api.client;
public record ReqResp<TData>(int status, TData data) {
}

View File

@ -1,19 +1,20 @@
package eu.mhsl.craftattack.spawn.api.client.repositories; package eu.mhsl.craftattack.spawn.api.client.repositories;
import eu.mhsl.craftattack.spawn.api.client.HttpRepository; import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.util.api.ApiUtil; import eu.mhsl.craftattack.spawn.util.api.ApiUtil;
import java.util.UUID; import java.util.UUID;
public class ReportRepository extends HttpRepository { public class ReportRepository extends HttpRepository {
public ReportRepository() { public ReportRepository() {
super(ApiUtil.getBaseUri()); super(ApiUtil.getBaseUri(), ApiUtil::withAuthorizationSecret);
} }
public record SendReportResponse(UUID user) {} public record SendReportResponse(UUID user) {}
public record ReportInput(UUID user) {} public record ReportInput(UUID user) {}
public RequestResponse<SendReportResponse> sendReport(ReportInput input) { public ReqResp<SendReportResponse> sendReport(ReportInput input) {
return this.post("reports", (builder) -> builder.addParameter("token", "asd"), input, SendReportResponse.class); return this.post("reports", (builder) -> builder.addParameter("token", "asd"), input, SendReportResponse.class);
} }
} }

View File

@ -0,0 +1,30 @@
package eu.mhsl.craftattack.spawn.api.client.repositories;
import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.util.api.ApiUtil;
import java.util.UUID;
public class WhitelistRepository extends HttpRepository {
public WhitelistRepository() {
super(ApiUtil.getBaseUri(), ApiUtil::withAuthorizationSecret);
}
public record UserData(
UUID uuid,
String username,
String firstname,
String lastname,
Long banned_until,
Long outlawed_until
) {}
public ReqResp<UserData> getUserData(UUID userId) {
return this.get(
"user",
uriBuilder -> uriBuilder.addParameter("uuid", userId.toString()),
UserData.class
);
}
}

View File

@ -4,7 +4,6 @@ import com.google.gson.Gson;
import eu.mhsl.craftattack.spawn.Main; import eu.mhsl.craftattack.spawn.Main;
import eu.mhsl.craftattack.spawn.appliance.Appliance; import eu.mhsl.craftattack.spawn.appliance.Appliance;
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.util.api.ApiUtil;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder; import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
@ -39,8 +38,8 @@ public class Report extends Appliance {
.build(); .build();
} }
private final URI apiEndpoint = ApiUtil.getReportEndpoint(); private URI apiEndpoint;
private final String apiSecret = ApiUtil.getApiSecret(); private String apiSecret;
public Report() { public Report() {
super("report"); super("report");

View File

@ -1,25 +1,19 @@
package eu.mhsl.craftattack.spawn.appliances.whitelist; package eu.mhsl.craftattack.spawn.appliances.whitelist;
import com.google.gson.Gson;
import eu.mhsl.craftattack.spawn.Main; import eu.mhsl.craftattack.spawn.Main;
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.api.client.repositories.WhitelistRepository;
import eu.mhsl.craftattack.spawn.api.server.HttpServer; import eu.mhsl.craftattack.spawn.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.appliance.Appliance; import eu.mhsl.craftattack.spawn.appliance.Appliance;
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed; import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
import eu.mhsl.craftattack.spawn.util.api.ApiUtil; import eu.mhsl.craftattack.spawn.util.api.HttpStatus;
import eu.mhsl.craftattack.spawn.util.server.Floodgate; import eu.mhsl.craftattack.spawn.util.server.Floodgate;
import eu.mhsl.craftattack.spawn.util.text.DisconnectInfo; import eu.mhsl.craftattack.spawn.util.text.DisconnectInfo;
import org.apache.http.client.utils.URIBuilder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -30,13 +24,6 @@ import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
public class Whitelist extends Appliance { public class Whitelist extends Appliance {
private record UserData(UUID uuid, String username, String firstname, String lastname, Long banned_until,
Long outlawed_until) {
}
private final URI apiEndpoint = ApiUtil.getWhitelistEndpoint();
private final String apiSecret = ApiUtil.getApiSecret();
public Whitelist() { public Whitelist() {
super("whitelist"); super("whitelist");
} }
@ -45,12 +32,12 @@ public class Whitelist extends Appliance {
try { try {
Main.instance().getLogger().info(String.format("Running integrityCheck for %s", player.getName())); Main.instance().getLogger().info(String.format("Running integrityCheck for %s", player.getName()));
boolean overrideCheck = localConfig().getBoolean("overrideIntegrityCheck", false); boolean overrideCheck = localConfig().getBoolean("overrideIntegrityCheck", false);
UserData user = overrideCheck WhitelistRepository.UserData user = overrideCheck
? new UserData(player.getUniqueId(), player.getName(), "", "", 0L, 0L) ? new WhitelistRepository.UserData(player.getUniqueId(), player.getName(), "", "", 0L, 0L)
: this.fetchUserData(player.getUniqueId()); : this.fetchUserData(player.getUniqueId());
if (timestampRelevant(user.banned_until)) { if (timestampRelevant(user.banned_until())) {
Instant bannedDate = new Date(user.banned_until * 1000L) Instant bannedDate = new Date(user.banned_until() * 1000L)
.toInstant() .toInstant()
.plus(1, ChronoUnit.HOURS); .plus(1, ChronoUnit.HOURS);
@ -65,16 +52,16 @@ public class Whitelist extends Appliance {
); );
} }
queryAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until)); queryAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until()));
String purePlayerName = Floodgate.isBedrock(player) String purePlayerName = Floodgate.isBedrock(player)
? Floodgate.getBedrockPlayer(player).getUsername() ? Floodgate.getBedrockPlayer(player).getUsername()
: player.getName(); : player.getName();
if (!user.username.trim().equalsIgnoreCase(purePlayerName)) if (!user.username().trim().equalsIgnoreCase(purePlayerName))
throw new DisconnectInfo.Throwable( throw new DisconnectInfo.Throwable(
"Nutzername geändert", "Nutzername geändert",
String.format("Der Name '%s' stimmt nicht mit '%s' überein.", user.username, player.getName()), String.format("Der Name '%s' stimmt nicht mit '%s' überein.", user.username(), player.getName()),
"Bitte kontaktiere einen Admin, um Deine Anmeldedaten zu aktualisieren!", "Bitte kontaktiere einen Admin, um Deine Anmeldedaten zu aktualisieren!",
player.getUniqueId() player.getUniqueId()
); );
@ -97,21 +84,10 @@ public class Whitelist extends Appliance {
return timestamp > System.currentTimeMillis() / 1000L; return timestamp > System.currentTimeMillis() / 1000L;
} }
private UserData fetchUserData(UUID uuid) throws DisconnectInfo.Throwable { private WhitelistRepository.UserData fetchUserData(UUID uuid) throws DisconnectInfo.Throwable {
URIBuilder uriBuilder = new URIBuilder(this.apiEndpoint); ReqResp<WhitelistRepository.UserData> response = this.queryRepository(WhitelistRepository.class).getUserData(uuid);
uriBuilder.addParameter("secret", this.apiSecret);
uriBuilder.addParameter("uuid", uuid.toString());
try(HttpClient client = HttpClient.newHttpClient()) { if(response.status() == HttpStatus.NOT_FOUND)
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(uriBuilder.build())
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
if(httpResponse.statusCode() == 404)
throw new DisconnectInfo.Throwable( throw new DisconnectInfo.Throwable(
"Nicht angemeldet", "Nicht angemeldet",
"Du bist derzeit nicht als Teilnehmer des CraftAttack-Projektes registriert!", "Du bist derzeit nicht als Teilnehmer des CraftAttack-Projektes registriert!",
@ -119,11 +95,7 @@ public class Whitelist extends Appliance {
uuid uuid
); );
return new Gson().fromJson(httpResponse.body(), UserData.class); return response.data();
} catch(IOException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e);
}
} }
@Override @Override

View File

@ -1,17 +1,17 @@
package eu.mhsl.craftattack.spawn.util.api; package eu.mhsl.craftattack.spawn.util.api;
import eu.mhsl.craftattack.spawn.config.Configuration; import eu.mhsl.craftattack.spawn.config.Configuration;
import org.apache.http.client.utils.URIBuilder;
import org.bukkit.configuration.ConfigurationSection;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Objects; import java.util.Objects;
public class ApiUtil { public class ApiUtil {
public final static String basePath = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api")) private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api"));
.getString("baseurl"); public final static String basePath = apiConfig.getString("baseurl");
public final static String apiSecret = apiConfig.getString("secret");
public final static String apiSecret = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api"))
.getString("secret");
public static URI getBaseUri() { public static URI getBaseUri() {
Objects.requireNonNull(basePath); Objects.requireNonNull(basePath);
@ -21,4 +21,8 @@ public class ApiUtil {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static void withAuthorizationSecret(URIBuilder builder) {
builder.addParameter("secret", apiSecret);
}
} }

View File

@ -0,0 +1,14 @@
package eu.mhsl.craftattack.spawn.util.api;
public class HttpStatus {
public static final int OK = 200;
public static final int CREATED = 201;
public static final int ACCEPTED = 202;
public static final int NO_CONTENT = 204;
public static final int BAD_REQUEST = 400;
public static final int UNAUTHORIZED = 401;
public static final int FORBIDDEN = 403;
public static final int NOT_FOUND = 404;
public static final int INTERNAL_SERVER_ERROR = 500;
public static final int SERVICE_UNAVAILABLE = 503;
}

View File

@ -3,10 +3,8 @@ plugin:
- NameOfApplianceClass - NameOfApplianceClass
api: api:
secret: qeeDmIXn@Wfye4@f8twTJkdNWr7Uz2byETKJBE9bfxz&M7VqOnuA3q3GT#WkwTVn secret: secret
baseurl: https://mhsl.eu/craftattack/api/ baseurl: https://mhsl.eu/craftattack/api/
report: report
whitelist: user
worldMuseum: worldMuseum:
uuid: uuid: