update
This commit is contained in:
1 parent
3f672d1819
commit
15d1c70b8c
5 files changed
+105
-101
No files matched your search
@@ -1,18 +1,17 @@
|
|||||||
package eu.mhsl.craftattack.loginServer;
|
package eu.mhsl.craftattack.loginServer;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Optional;
|
import java.util.Base64;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public final class Api {
|
public final class Api {
|
||||||
@@ -20,67 +19,78 @@ public final class Api {
|
|||||||
|
|
||||||
private Api() {}
|
private Api() {}
|
||||||
|
|
||||||
public static void setProfile(UUID uuid, String username, String name, String secondName, String birthday, String phoneNumber) {
|
|
||||||
JsonObject body = new JsonObject();
|
|
||||||
body.addProperty("uuid", uuid.toString());
|
|
||||||
body.addProperty("username", username);
|
|
||||||
body.addProperty("name", name);
|
|
||||||
body.addProperty("secondName", secondName);
|
|
||||||
body.addProperty("birthday", birthday);
|
|
||||||
body.addProperty("phoneNumber", phoneNumber);
|
|
||||||
|
|
||||||
send("POST", "players", "", body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isRegistered(UUID uuid) {
|
public static boolean isRegistered(UUID uuid) {
|
||||||
return find("players", "uuid", uuid.toString()).isPresent();
|
HttpResponse<String> response = call("GET", "/api/users/" + uuid, null, true);
|
||||||
|
int status = response.statusCode();
|
||||||
|
if (status == 200) return true;
|
||||||
|
if (status == 404) return false;
|
||||||
|
throw new IllegalStateException("API-Fehler " + status + ": " + response.body());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSecretValid(String username, String secret) {
|
public static final class SignupError extends RuntimeException {
|
||||||
return find("secrets", "player", username, "secret", secret).isPresent();
|
public final String code;
|
||||||
}
|
public SignupError(String code, String message) {
|
||||||
|
super(message);
|
||||||
private static Optional<JsonObject> find(String collection, String... fieldValuePairs) {
|
this.code = code;
|
||||||
StringBuilder filter = new StringBuilder();
|
|
||||||
for (int i = 0; i < fieldValuePairs.length; i += 2) {
|
|
||||||
if (i > 0) filter.append(" && ");
|
|
||||||
String escaped = fieldValuePairs[i + 1].replace("\\", "\\\\").replace("'", "\\'");
|
|
||||||
filter.append(fieldValuePairs[i]).append("='").append(escaped).append("'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String query = "?perPage=1&filter=" + URLEncoder.encode(filter.toString(), StandardCharsets.UTF_8);
|
|
||||||
JsonObject response = send("GET", collection, query, null);
|
|
||||||
if (!response.has("items")) return Optional.empty();
|
|
||||||
JsonArray items = response.getAsJsonArray("items");
|
|
||||||
return items.isEmpty() ? Optional.empty() : Optional.of(items.get(0).getAsJsonObject());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonObject send(String method, String collection, String path, JsonObject body) {
|
public static void signup(
|
||||||
JsonObject login = new JsonObject();
|
String firstname,
|
||||||
login.addProperty("identity", config("email"));
|
String lastname,
|
||||||
login.addProperty("password", config("password"));
|
String birthdayIso,
|
||||||
|
String phone,
|
||||||
|
String username,
|
||||||
|
UUID uuid,
|
||||||
|
String edition
|
||||||
|
) {
|
||||||
|
JsonObject body = new JsonObject();
|
||||||
|
body.addProperty("firstname", firstname);
|
||||||
|
body.addProperty("lastname", lastname);
|
||||||
|
body.addProperty("birthday", birthdayIso);
|
||||||
|
body.addProperty("phone", phone);
|
||||||
|
body.addProperty("username", username);
|
||||||
|
body.addProperty("uuid", uuid.toString());
|
||||||
|
body.addProperty("edition", edition);
|
||||||
|
|
||||||
String token = call("POST", "/api/collections/_superusers/auth-with-password", login, null)
|
HttpResponse<String> response = call("POST", "/api/users", body.toString(), true);
|
||||||
.get("token").getAsString();
|
int status = response.statusCode();
|
||||||
return call(method, "/api/collections/" + collection + "/records" + path, body, token);
|
if (status >= 200 && status < 300) return;
|
||||||
|
|
||||||
|
String code = switch (status) {
|
||||||
|
case 400 -> "BAD_REQUEST";
|
||||||
|
case 401 -> "UNAUTHORIZED";
|
||||||
|
case 409 -> "CONFLICT";
|
||||||
|
default -> "UNKNOWN";
|
||||||
|
};
|
||||||
|
String message = response.body();
|
||||||
|
try {
|
||||||
|
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
|
||||||
|
JsonElement error = json.get("error");
|
||||||
|
if (error != null && error.isJsonPrimitive()) message = error.getAsString();
|
||||||
|
} catch (RuntimeException ignored) {}
|
||||||
|
throw new SignupError(code, "Signup fehlgeschlagen (" + status + "/" + code + "): " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonObject call(String method, String path, JsonObject body, String token) {
|
private static HttpResponse<String> call(String method, String path, String body, boolean withAuth) {
|
||||||
try {
|
try {
|
||||||
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(config("url") + path))
|
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(config("url") + path))
|
||||||
.timeout(Duration.ofSeconds(5))
|
.timeout(Duration.ofSeconds(5))
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.method(method, body == null
|
.method(method, body == null
|
||||||
? HttpRequest.BodyPublishers.noBody()
|
? HttpRequest.BodyPublishers.noBody()
|
||||||
: HttpRequest.BodyPublishers.ofString(body.toString()));
|
: HttpRequest.BodyPublishers.ofString(body));
|
||||||
if (token != null) builder.header("Authorization", token);
|
|
||||||
|
|
||||||
HttpResponse<String> response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
|
if (withAuth) {
|
||||||
if (response.statusCode() >= 300) {
|
String secret = config("secret");
|
||||||
throw new IllegalStateException("API-Fehler " + response.statusCode() + ": " + response.body());
|
if (!secret.isBlank()) {
|
||||||
|
String credentials = Base64.getEncoder()
|
||||||
|
.encodeToString(("api:" + secret).getBytes(StandardCharsets.UTF_8));
|
||||||
|
builder.header("Authorization", "Basic " + credentials);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (response.body().isBlank()) return new JsonObject();
|
|
||||||
return JsonParser.parseString(response.body()).getAsJsonObject();
|
return client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
throw new IllegalStateException("API nicht erreichbar", e);
|
throw new IllegalStateException("API nicht erreichbar", e);
|
||||||
}
|
}
|
||||||
@@ -89,12 +99,4 @@ public final class Api {
|
|||||||
private static String config(String key) {
|
private static String config(String key) {
|
||||||
return Main.globalConfig.node("api", key).getString("");
|
return Main.globalConfig.node("api", key).getString("");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public static boolean removeSecret(String username, String secret) {
|
|
||||||
Optional<JsonObject> entry = find("secrets", "player", username, "secret", secret);
|
|
||||||
if (entry.isEmpty()) return false;
|
|
||||||
|
|
||||||
send("DELETE", "secrets", "/" + entry.get().get("id").getAsString(), null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -83,11 +83,6 @@ public final class Dialog {
|
|||||||
String title;
|
String title;
|
||||||
|
|
||||||
switch (state.currentPage()) {
|
switch (state.currentPage()) {
|
||||||
case secret -> {
|
|
||||||
title = "Secret";
|
|
||||||
body.add(plain("Bitte gib das Secret ein, das du erhalten hast."));
|
|
||||||
inputs.add(text("secret", "Secret", state.secret, 50));
|
|
||||||
}
|
|
||||||
case data -> {
|
case data -> {
|
||||||
title = "Profildaten";
|
title = "Profildaten";
|
||||||
body.add(plain("Bitte fülle deine Profildaten aus."));
|
body.add(plain("Bitte fülle deine Profildaten aus."));
|
||||||
@@ -158,7 +153,6 @@ public final class Dialog {
|
|||||||
|
|
||||||
private static void saveCurrentPage(DialogState state, CompoundBinaryTag payload) {
|
private static void saveCurrentPage(DialogState state, CompoundBinaryTag payload) {
|
||||||
switch (state.currentPage()) {
|
switch (state.currentPage()) {
|
||||||
case secret -> state.secret = payload.getString("secret", "").trim();
|
|
||||||
case data -> {
|
case data -> {
|
||||||
state.firstName = payload.getString("name", "").trim();
|
state.firstName = payload.getString("name", "").trim();
|
||||||
state.secondName = payload.getString("secondName", "").trim();
|
state.secondName = payload.getString("secondName", "").trim();
|
||||||
@@ -175,15 +169,6 @@ public final class Dialog {
|
|||||||
|
|
||||||
private static Component validateCurrentPage(Player player, DialogState state) {
|
private static Component validateCurrentPage(Player player, DialogState state) {
|
||||||
switch (state.currentPage()) {
|
switch (state.currentPage()) {
|
||||||
case secret -> {
|
|
||||||
try {
|
|
||||||
if (!Api.isSecretValid(player.getUsername(), state.secret))
|
|
||||||
return error("Das Secret ist ungültig.");
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return error("Die Überprüfung ist gerade nicht möglich. Bitte versuche es später erneut.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case data -> {
|
case data -> {
|
||||||
if (state.firstName.isBlank() || state.secondName.isBlank() || state.birthday.isBlank())
|
if (state.firstName.isBlank() || state.secondName.isBlank() || state.birthday.isBlank())
|
||||||
return error("Bitte fülle alle Pflichtfelder aus.");
|
return error("Bitte fülle alle Pflichtfelder aus.");
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ package eu.mhsl.craftattack.loginServer;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class DialogState {
|
public final class DialogState {
|
||||||
public enum Page { secret, data, consent }
|
public enum Page { data, consent }
|
||||||
|
|
||||||
private final List<Page> pages;
|
private static final List<Page> pages = List.of(Page.data, Page.consent);
|
||||||
private int pageIndex = 0;
|
private int pageIndex = 0;
|
||||||
|
|
||||||
String secret = "";
|
|
||||||
String firstName = "";
|
String firstName = "";
|
||||||
String secondName = "";
|
String secondName = "";
|
||||||
String birthday = "";
|
String birthday = "";
|
||||||
@@ -17,18 +16,10 @@ public final class DialogState {
|
|||||||
boolean logsAccepted = false;
|
boolean logsAccepted = false;
|
||||||
boolean rulesAccepted = false;
|
boolean rulesAccepted = false;
|
||||||
|
|
||||||
private DialogState(List<Page> pages) {
|
private DialogState() {}
|
||||||
this.pages = pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DialogState create() {
|
public static DialogState create() {
|
||||||
boolean isAfterStart = Main.globalConfig
|
return new DialogState();
|
||||||
.node("server", "is-after-start")
|
|
||||||
.getBoolean(false);
|
|
||||||
|
|
||||||
return new DialogState(isAfterStart
|
|
||||||
? List.of(Page.secret, Page.data, Page.consent)
|
|
||||||
: List.of(Page.data, Page.consent));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page currentPage() {
|
public Page currentPage() {
|
||||||
@@ -58,4 +49,4 @@ public final class DialogState {
|
|||||||
public void previousPage() {
|
public void previousPage() {
|
||||||
pageIndex = Math.max(0, pageIndex - 1);
|
pageIndex = Math.max(0, pageIndex - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.loginServer;
|
package eu.mhsl.craftattack.loginServer;
|
||||||
|
|
||||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
@@ -9,6 +10,9 @@ import net.minestom.server.event.player.PlayerCustomClickEvent;
|
|||||||
import net.minestom.server.instance.InstanceManager;
|
import net.minestom.server.instance.InstanceManager;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -53,27 +57,51 @@ public final class PlayerHandler {
|
|||||||
private static void complete(Player player, DialogState state) {
|
private static void complete(Player player, DialogState state) {
|
||||||
states.remove(player.getUuid());
|
states.remove(player.getUuid());
|
||||||
|
|
||||||
if (Api.isRegistered(player.getUuid())) {
|
String birthdayIso;
|
||||||
player.kick("Du bist bereits auf Craftattack registriert, wir freuen uns auf dich!");
|
try {
|
||||||
|
birthdayIso = LocalDate
|
||||||
|
.parse(state.birthday, DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.GERMANY))
|
||||||
|
.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
player.kick(Component.text("Geburtsdatum ungültig."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Api.signup(
|
||||||
|
state.firstName,
|
||||||
|
state.secondName,
|
||||||
|
birthdayIso,
|
||||||
|
state.phoneNumber,
|
||||||
|
player.getUsername(),
|
||||||
|
player.getUuid(),
|
||||||
|
"java"
|
||||||
|
);
|
||||||
|
} catch (Api.SignupError e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
player.kick(Component.text(mapSignupError(e)));
|
||||||
|
return;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
player.kick(Component.text("Anmeldung gerade nicht möglich. Bitte später erneut versuchen."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage("Danke für deine Anmeldung.");
|
player.sendMessage("Danke für deine Anmeldung.");
|
||||||
player.sendMessage("Du bist für das Projekt Craftattack 9 registriert!");
|
player.sendMessage("Du bist für das Projekt Craftattack 9 registriert!");
|
||||||
|
|
||||||
Api.setProfile(player.getUuid(), player.getUsername(), state.firstName, state.secondName, state.birthday, state.phoneNumber);
|
|
||||||
Api.removeSecret(player.getUsername(), state.secret);
|
|
||||||
|
|
||||||
MinecraftServer.getSchedulerManager()
|
MinecraftServer.getSchedulerManager()
|
||||||
.buildTask(() -> player.kick("Anmeldung erfolgreich, wir freuen uns auf dich!"))
|
.buildTask(() -> player.kick("Anmeldung erfolgreich, wir freuen uns auf dich!"))
|
||||||
.delay(Duration.ofMillis(1000))
|
.delay(Duration.ofMillis(1000))
|
||||||
.schedule();
|
.schedule();
|
||||||
|
|
||||||
System.out.println("Vorname: " + state.firstName);
|
|
||||||
System.out.println("Nachname: " + state.secondName);
|
|
||||||
System.out.println("Geburtstag: " + state.birthday);
|
|
||||||
System.out.println("Telefonnummer: " + state.phoneNumber);
|
|
||||||
System.out.println("Spielername: " + player.getUsername());
|
|
||||||
System.out.println("Spieler UUID: " + player.getUuid());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static String mapSignupError(Api.SignupError e) {
|
||||||
|
return switch (e.code) {
|
||||||
|
case "CONFLICT" -> "Du bist bereits registriert.";
|
||||||
|
case "UNAUTHORIZED" -> "Server nicht autorisiert. Bitte Admin kontaktieren.";
|
||||||
|
case "BAD_REQUEST" -> "Deine Angaben sind nicht gültig.";
|
||||||
|
default -> "Anmeldung fehlgeschlagen. Bitte später erneut versuchen.";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ server:
|
|||||||
view-distance: 12
|
view-distance: 12
|
||||||
compression-threshold: 0
|
compression-threshold: 0
|
||||||
open-to-lan: false
|
open-to-lan: false
|
||||||
is-after-start: false
|
|
||||||
|
|
||||||
bungeecord:
|
bungeecord:
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -15,5 +14,4 @@ velocity:
|
|||||||
|
|
||||||
api:
|
api:
|
||||||
url: ""
|
url: ""
|
||||||
email: ""
|
secret: ""
|
||||||
password: ""
|
|
||||||
Reference in new issue
Block a user