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 48e774677edf17d4a99ae9ed23d1b371dab41abb..21409ff86db65c00d92bff9eae8bdeb3a872a361 100644 --- a/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java +++ b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java @@ -11,7 +11,7 @@ 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); diff --git a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService.java b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService.java index bfc1e27c37689c1fbb927404a7176780a439a057..bc8ab50ef1390a2c51110a89dc43db58215396a9 100644 --- a/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService.java +++ b/src/main/java/com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService.java @@ -46,7 +46,7 @@ import java.util.stream.Collectors; public class YggdrasilMinecraftSessionService implements MinecraftSessionService { private static final Logger LOGGER = LoggerFactory.getLogger(YggdrasilMinecraftSessionService.class); - private final MinecraftClient client; + protected final MinecraftClient client; // Leaves - private -> protected private final ServicesKeySet servicesKeySet; private final String baseUrl; private final URL joinUrl; diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java index 7573c12a77797146c51ef2dfe4b2a636df45e21a..458c69eee97a5284b8e7658450cbac32a52137fe 100644 --- a/src/main/java/net/minecraft/server/Main.java +++ b/src/main/java/net/minecraft/server/Main.java @@ -198,7 +198,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/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 89a50e07bc79cb0d5353f5a06fa037f3942c5940..760b1fb833fea279062965002686b57f967a5eaf 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -260,7 +260,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop public private long lastServerStatus; public final Thread serverThread; private long nextTickTimeNanos; diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java index dd8c222661a7facb6f9cd64e19676cfe4eee50a6..94beb47e3ebc5dca07b388ee856c1bfe820e2174 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 top.leavesmc.leaves.command.LeavesCommand; 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; @@ -529,6 +530,9 @@ public final class LeavesConfig { extraYggdrasilLoginProtect = getBoolean("settings.misc.extra-yggdrasil-service.login-protect", extraYggdrasilLoginProtect); 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(); } } 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..3da207a13fce243bf880c8a4f7054cf20997991d --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/profile/LeavesAuthenticationService.java @@ -0,0 +1,18 @@ +package top.leavesmc.leaves.profile; + +import com.destroystokyo.paper.profile.PaperAuthenticationService; +import com.mojang.authlib.minecraft.MinecraftSessionService; + +import java.net.Proxy; + +public class LeavesAuthenticationService extends PaperAuthenticationService { + + public LeavesAuthenticationService(Proxy proxy) { + super(proxy); + } + + @Override + public MinecraftSessionService createMinecraftSessionService() { + return new LeavesMinecraftSessionService(this.getServicesKeySet(), this.getProxy(), this.environment); + } +} 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..9bfa0d0c12ac2a44968cd39b6d9f406defb23c07 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/profile/LeavesMinecraftSessionService.java @@ -0,0 +1,102 @@ +package top.leavesmc.leaves.profile; + +import com.destroystokyo.paper.profile.PaperMinecraftSessionService; +import com.mojang.authlib.Environment; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.HttpAuthenticationService; +import com.mojang.authlib.exceptions.AuthenticationUnavailableException; +import com.mojang.authlib.exceptions.MinecraftClientException; +import com.mojang.authlib.yggdrasil.ProfileActionType; +import com.mojang.authlib.yggdrasil.ProfileResult; +import com.mojang.authlib.yggdrasil.ServicesKeySet; +import com.mojang.authlib.yggdrasil.response.HasJoinedMinecraftServerResponse; +import com.mojang.authlib.yggdrasil.response.ProfileAction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import org.jetbrains.annotations.Nullable; +import top.leavesmc.leaves.LeavesConfig; +import top.leavesmc.leaves.bot.ServerBot; + +import java.net.InetAddress; +import java.net.Proxy; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class LeavesMinecraftSessionService extends PaperMinecraftSessionService { + + protected LeavesMinecraftSessionService(ServicesKeySet keySet, Proxy authenticationService, Environment environment) { + super(keySet, authenticationService, environment); + } + + private static List extraYggdrasilList = List.of(); + + public static void initExtraYggdrasilList() { + List list = new ArrayList<>(); + for (String str : LeavesConfig.extraYggdrasilServiceList) { + list.add(HttpAuthenticationService.constantURL(str + "/sessionserver/session/minecraft/hasJoined")); + } + extraYggdrasilList = Collections.unmodifiableList(list); + } + + @Nullable + @Override + public ProfileResult hasJoinedServer(String profileName, String serverId, @Nullable InetAddress address) throws AuthenticationUnavailableException { + ProfileResult result = super.hasJoinedServer(profileName, serverId, address); // mojang + + ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayerByName(profileName); + if (player != null && !(player instanceof ServerBot)) { + return null; // if it has same name, return null + } + + if (LeavesConfig.extraYggdrasilService && result == null) { + final Map arguments = new HashMap<>(); + arguments.put("username", profileName); + arguments.put("serverId", serverId); + + if (address != null) { + arguments.put("ip", address.getHostAddress()); + } + + GameProfile cache = null; + if (LeavesConfig.extraYggdrasilLoginProtect) { + cache = MinecraftServer.getServer().services.profileCache().getProfileIfCached(profileName); + } + + for (URL checkUrl : extraYggdrasilList) { + URL url = HttpAuthenticationService.concatenateURL(checkUrl, HttpAuthenticationService.buildQuery(arguments)); + try { + final HasJoinedMinecraftServerResponse response = client.get(url, HasJoinedMinecraftServerResponse.class); + if (response != null && response.id() != null) { + if (LeavesConfig.extraYggdrasilLoginProtect && cache != null) { + if (response.id() != cache.getId()) { + continue; + } + } + + final GameProfile result1 = new GameProfile(response.id(), profileName); + + if (response.properties() != null) { + result1.getProperties().putAll(response.properties()); + } + + final Set profileActions = response.profileActions().stream() + .map(ProfileAction::type) + .collect(Collectors.toSet()); + return new ProfileResult(result1, profileActions); + } + } catch (final MinecraftClientException e) { + if (e.toAuthenticationException() instanceof final AuthenticationUnavailableException unavailable) { + throw unavailable; + } + } + } + } + return result; + } +}