9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-26 18:39:08 +00:00
Files
LeavesMC/patches/server/0059-Leaves-Extra-Yggdrasil-Service.patch

270 lines
13 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Thu, 2 Feb 2023 16:01:18 +0800
Subject: [PATCH] Leaves Extra Yggdrasil Service
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
index 1459a1f99fe614d072a087cda18788cf13102645..73bfda834fa704b208a5dd9271bb397a9f8b5983 100644
--- a/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
@@ -8,7 +8,7 @@ import com.mojang.authlib.yggdrasil.YggdrasilEnvironment;
import java.net.Proxy;
public class PaperAuthenticationService extends YggdrasilAuthenticationService {
- private final Environment environment;
+ protected final Environment environment; // Leaves - private -> protected
public PaperAuthenticationService(Proxy proxy) {
super(proxy);
this.environment = EnvironmentParser.getEnvironmentFromProperties().orElse(YggdrasilEnvironment.PROD.getEnvironment());
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 31faf2d6492696f7d0c99a48edbc0d6f15db1209..c7a2838157d73fa613e154aabb0d0a65f672fd55 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -181,7 +181,7 @@ public class Main {
file = new File(bukkitConfiguration.getString("settings.world-container", "."));
}
// Paper end - fix SPIGOT-5824
- Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper
+ Services services = Services.create(new top.leavesmc.leaves.profile.LeavesAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper // Leaves - extra-yggdrasil-service
// CraftBukkit start
String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName);
LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath());
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index f4b8146b253482ddc73485168c30b43bc42b9456..8df4bfb5e976369194e02dea0327830d6510d09a 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -11,6 +11,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.spigotmc.SpigotConfig;
import top.leavesmc.leaves.bot.BotCommand;
import top.leavesmc.leaves.bot.agent.Actions;
+import top.leavesmc.leaves.profile.LeavesMinecraftSessionService;
import top.leavesmc.leaves.util.MathUtils;
import java.io.File;
@@ -496,6 +497,18 @@ public final class LeavesConfig {
xaeroMapServerID = getInt("settings.protocol.xaero-map-server-id", xaeroMapServerID);
}
+ public static boolean extraYggdrasilService = false;
+ public static List<String> extraYggdrasilServiceList = List.of("https://url.with.authlib-injector-yggdrasil");
+ private static void extraYggdrasilService() {
+ extraYggdrasilService = getBoolean("settings.misc.extra-yggdrasil-service.enable", extraYggdrasilService);
+ extraYggdrasilServiceList = getList("settings.misc.extra-yggdrasil-service.urls", extraYggdrasilServiceList);
+ if (extraYggdrasilService) {
+ LeavesLogger.LOGGER.warning("extra-yggdrasil-service is an unofficial support. Enabling it may cause data security problems!");
+ GlobalConfiguration.get().unsupportedSettings.performUsernameValidation = true; // always check user name
+ LeavesMinecraftSessionService.initExtraYggdrasilList();
+ }
+ }
+
public static final class WorldConfig {
public final String worldName;
diff --git a/src/main/java/top/leavesmc/leaves/profile/LeavesAuthenticationService.java b/src/main/java/top/leavesmc/leaves/profile/LeavesAuthenticationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee10e314a7e1af28ea008123f75caee26515b692
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/profile/LeavesAuthenticationService.java
@@ -0,0 +1,103 @@
+package top.leavesmc.leaves.profile;
+
+import com.destroystokyo.paper.profile.PaperAuthenticationService;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.exceptions.AuthenticationException;
+import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
+import com.mojang.authlib.exceptions.InsufficientPrivilegesException;
+import com.mojang.authlib.exceptions.InvalidCredentialsException;
+import com.mojang.authlib.exceptions.UserBannedException;
+import com.mojang.authlib.exceptions.UserMigratedException;
+import com.mojang.authlib.minecraft.MinecraftSessionService;
+import com.mojang.authlib.properties.PropertyMap;
+import com.mojang.authlib.yggdrasil.response.HasJoinedMinecraftServerResponse;
+import com.mojang.authlib.yggdrasil.response.ProfileSearchResultsResponse;
+import com.mojang.util.UUIDTypeAdapter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.UUID;
+
+public class LeavesAuthenticationService extends PaperAuthenticationService {
+
+ protected final Gson gson;
+
+ public LeavesAuthenticationService(Proxy proxy) {
+ super(proxy);
+
+ GsonBuilder builder = new GsonBuilder();
+ builder.registerTypeAdapter(GameProfile.class, new GameProfileSerializer());
+ builder.registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer());
+ builder.registerTypeAdapter(UUID.class, new UUIDTypeAdapter());
+ builder.registerTypeAdapter(ProfileSearchResultsResponse.class, new ProfileSearchResultsResponse.Serializer());
+ this.gson = builder.create();
+ }
+
+ @Override
+ public MinecraftSessionService createMinecraftSessionService() {
+ return new LeavesMinecraftSessionService(this, this.environment);
+ }
+
+ public HasJoinedMinecraftServerResponse makeHasJoinResponse(URL url) throws AuthenticationException {
+ try {
+ String jsonResult = performGetRequest(url, null);
+ HasJoinedMinecraftServerResponse result = this.gson.fromJson(jsonResult, HasJoinedMinecraftServerResponse.class);
+ if (result == null) {
+ return null;
+ } else if (StringUtils.isNotBlank(result.getError())) {
+ if ("UserMigratedException".equals(result.getCause())) {
+ throw new UserMigratedException(result.getErrorMessage());
+ } else if ("ForbiddenOperationException".equals(result.getError())) {
+ throw new InvalidCredentialsException(result.getErrorMessage());
+ } else if ("InsufficientPrivilegesException".equals(result.getError())) {
+ throw new InsufficientPrivilegesException(result.getErrorMessage());
+ } else if ("multiplayer.access.banned".equals(result.getError())) {
+ throw new UserBannedException();
+ } else {
+ throw new AuthenticationException(result.getErrorMessage());
+ }
+ } else {
+ return result;
+ }
+ } catch (IllegalStateException | JsonParseException | IOException var7) {
+ throw new AuthenticationUnavailableException("Cannot contact authentication server", var7);
+ }
+ }
+
+ public static class GameProfileSerializer implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile> {
+ private GameProfileSerializer() {
+ }
+
+ public GameProfile deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ JsonObject object = (JsonObject)json;
+ UUID id = object.has("id") ? (UUID)context.deserialize(object.get("id"), UUID.class) : null;
+ String name = object.has("name") ? object.getAsJsonPrimitive("name").getAsString() : null;
+ return new GameProfile(id, name);
+ }
+
+ public JsonElement serialize(GameProfile src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject result = new JsonObject();
+ if (src.getId() != null) {
+ result.add("id", context.serialize(src.getId()));
+ }
+
+ if (src.getName() != null) {
+ result.addProperty("name", src.getName());
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/profile/LeavesMinecraftSessionService.java b/src/main/java/top/leavesmc/leaves/profile/LeavesMinecraftSessionService.java
new file mode 100644
index 0000000000000000000000000000000000000000..98ef48c9e47d2aff31bb326dd30a246cac94f55f
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/profile/LeavesMinecraftSessionService.java
@@ -0,0 +1,91 @@
+package top.leavesmc.leaves.profile;
+
+import com.destroystokyo.paper.profile.PaperMinecraftSessionService;
+import com.google.gson.JsonParseException;
+import com.mojang.authlib.Environment;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.HttpAuthenticationService;
+import com.mojang.authlib.exceptions.AuthenticationException;
+import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
+import com.mojang.authlib.exceptions.InsufficientPrivilegesException;
+import com.mojang.authlib.exceptions.InvalidCredentialsException;
+import com.mojang.authlib.exceptions.UserBannedException;
+import com.mojang.authlib.exceptions.UserMigratedException;
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
+import com.mojang.authlib.yggdrasil.response.HasJoinedMinecraftServerResponse;
+import com.mojang.authlib.yggdrasil.response.Response;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerPlayer;
+import org.apache.commons.lang3.StringUtils;
+import top.leavesmc.leaves.LeavesConfig;
+import top.leavesmc.leaves.bot.ServerBot;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LeavesMinecraftSessionService extends PaperMinecraftSessionService {
+
+ protected LeavesMinecraftSessionService(LeavesAuthenticationService authenticationService, Environment environment) {
+ super(authenticationService, environment);
+ }
+
+ private static List<URL> extraYggdrasilList = List.of();
+
+ public static void initExtraYggdrasilList() {
+ List<URL> list = new ArrayList<>();
+ for (String str : LeavesConfig.extraYggdrasilServiceList) {
+ list.add(HttpAuthenticationService.constantURL(str + "/sessionserver/session/minecraft/hasJoined"));
+ }
+ extraYggdrasilList = Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public LeavesAuthenticationService getAuthenticationService() {
+ return (LeavesAuthenticationService) super.getAuthenticationService();
+ }
+
+ @Override
+ public GameProfile hasJoinedServer(GameProfile user, String serverId, InetAddress address) throws AuthenticationUnavailableException {
+ GameProfile result = super.hasJoinedServer(user, serverId, address); // mojang result
+
+ ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayerByName(user.getName());
+ if (player != null && !(player instanceof ServerBot)) {
+ return null; // if it has same name, return null
+ }
+
+ if (LeavesConfig.extraYggdrasilService && result == null) {
+ Map<String, Object> arguments = new HashMap<>();
+ arguments.put("username", user.getName());
+ arguments.put("serverId", serverId);
+ if (address != null) {
+ arguments.put("ip", address.getHostAddress());
+ }
+
+ for (URL checkUrl : extraYggdrasilList) {
+ URL url = HttpAuthenticationService.concatenateURL(checkUrl, HttpAuthenticationService.buildQuery(arguments));
+
+ try {
+ HasJoinedMinecraftServerResponse response = this.getAuthenticationService().makeHasJoinResponse(url);
+ if (response != null && response.getId() != null) {
+ result = new GameProfile(response.getId(), user.getName());
+ if (response.getProperties() != null) {
+ result.getProperties().putAll(response.getProperties());
+ }
+ return result;
+ }
+ } catch (AuthenticationUnavailableException var8) {
+ throw var8;
+ } catch (AuthenticationException ignored) {
+ }
+ }
+ }
+
+ return result;
+ }
+}