Fix fucking bukkit injection
Dieser Commit ist enthalten in:
Ursprung
65bef9f2b6
Commit
00af00dfe8
@ -13,8 +13,8 @@ public class AltAuthBukkit extends JavaPlugin {
|
||||
@Setter
|
||||
private static JavaPlugin instance;
|
||||
|
||||
private SessionServiceInjector serviceInjector;
|
||||
private EncryptionRequestInjector requestInjector;
|
||||
private ServerIdInjector serverIdInjector;
|
||||
private AltAuthSessionService serviceInjector;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
@ -26,15 +26,13 @@ public class AltAuthBukkit extends JavaPlugin {
|
||||
saveDefaultConfig();
|
||||
String altAuthServer = getConfig().getString("altauth-proxy");
|
||||
|
||||
ProtocolInjector.init();
|
||||
serviceInjector = new SessionServiceInjector(altAuthServer);
|
||||
requestInjector = new EncryptionRequestInjector(altAuthServer);
|
||||
serverIdInjector = new ServerIdInjector(this, altAuthServer);
|
||||
serviceInjector = new AltAuthSessionService(serverIdInjector, altAuthServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
requestInjector.remove();
|
||||
serviceInjector.revert();
|
||||
ProtocolInjector.instance.close();
|
||||
serverIdInjector.close();
|
||||
}
|
||||
}
|
||||
|
146
bukkit/src/de/lixfel/altauth/bukkit/AltAuthSessionService.java
Normale Datei
146
bukkit/src/de/lixfel/altauth/bukkit/AltAuthSessionService.java
Normale Datei
@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package de.lixfel.altauth.bukkit;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.GameProfileRepository;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
|
||||
import de.lixfel.ReflectionUtil;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class AltAuthSessionService implements MinecraftSessionService {
|
||||
|
||||
private static final ReflectionUtil.FieldWrapper<URL> CHECK_URL = ReflectionUtil.getField(YggdrasilMinecraftSessionService.class, URL.class, 1);
|
||||
private static final boolean URL_STATIC = ReflectionUtil.MINECRAFT_VERSION < 17; //TODO maybe 16 (untested)
|
||||
|
||||
private static final Function<AltAuthSessionService, YggdrasilMinecraftSessionService> swapService;
|
||||
private static final Consumer<AltAuthSessionService> revertService;
|
||||
|
||||
static {
|
||||
if (ReflectionUtil.MINECRAFT_VERSION < 19) {
|
||||
ReflectionUtil.FieldWrapper<MinecraftSessionService> getService = ReflectionUtil.getField(ServerIdInjector.minecraftServer, MinecraftSessionService.class, 0);
|
||||
|
||||
swapService = altAuthService -> {
|
||||
Object minecraftServer = altAuthService.serverIdInjector.minecraftServerInstance();
|
||||
YggdrasilMinecraftSessionService service = (YggdrasilMinecraftSessionService) getService.get(minecraftServer);
|
||||
getService.set(minecraftServer, altAuthService);
|
||||
return service;
|
||||
};
|
||||
revertService = altAuthService -> getService.set(altAuthService.serverIdInjector.minecraftServerInstance(), altAuthService.service);
|
||||
} else {
|
||||
Class<?> services = ReflectionUtil.getClass("net.minecraft.server.Services");
|
||||
ReflectionUtil.FieldWrapper<?> getServices = ReflectionUtil.getField(ServerIdInjector.minecraftServer, services, 0);
|
||||
ReflectionUtil.FieldWrapper<MinecraftSessionService> getSessionService = ReflectionUtil.getField(services, MinecraftSessionService.class, 0);
|
||||
Class<?> signatureValidator = ReflectionUtil.getClass("net.minecraft.util.SignatureValidator");
|
||||
ReflectionUtil.FieldWrapper<?> getSignatureValidator = ReflectionUtil.getField(services, signatureValidator, 0);
|
||||
ReflectionUtil.FieldWrapper<GameProfileRepository> getGameProfileRepository = ReflectionUtil.getField(services, GameProfileRepository.class, 0);
|
||||
Class<?> userCache = ReflectionUtil.getClass("net.minecraft.server.players.UserCache");
|
||||
ReflectionUtil.FieldWrapper<?> getUserCache = ReflectionUtil.getField(services, userCache, 0);
|
||||
|
||||
Constructor<?> constructor;
|
||||
try {
|
||||
constructor = services.getConstructor(MinecraftSessionService.class, signatureValidator, GameProfileRepository.class, userCache);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
swapService = altAuthService -> {
|
||||
Object servicesInstance = getServices.get(altAuthService.serverIdInjector.minecraftServerInstance());
|
||||
|
||||
try {
|
||||
getServices.set(
|
||||
altAuthService.serverIdInjector.minecraftServerInstance(),
|
||||
constructor.newInstance(altAuthService, getSignatureValidator.get(servicesInstance), getGameProfileRepository.get(servicesInstance), getUserCache.get(servicesInstance))
|
||||
);
|
||||
} catch (InstantiationException | IllegalAccessException| InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return (YggdrasilMinecraftSessionService) getSessionService.get(servicesInstance);
|
||||
};
|
||||
revertService = altAuthService -> {
|
||||
Object servicesInstance = getServices.get(altAuthService.serverIdInjector.minecraftServerInstance());
|
||||
|
||||
try {
|
||||
getServices.set(
|
||||
altAuthService.serverIdInjector.minecraftServerInstance(),
|
||||
constructor.newInstance(altAuthService.service, getSignatureValidator.get(servicesInstance), getGameProfileRepository.get(servicesInstance), getUserCache.get(servicesInstance))
|
||||
);
|
||||
} catch (InstantiationException | IllegalAccessException| InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> minecraftEncryption = ReflectionUtil.getClass("net.minecraft.util.MinecraftEncryption");
|
||||
private static final ReflectionUtil.MethodWrapper getServerHash = ReflectionUtil.getMethod(minecraftEncryption, byte[].class, null, String.class, PublicKey.class, SecretKey.class);
|
||||
private static final ReflectionUtil.MethodWrapper getSecretKey = ReflectionUtil.getMethod(minecraftEncryption, null, PrivateKey.class, byte[].class);
|
||||
|
||||
private static final ReflectionUtil.FieldWrapper<KeyPair> getKeyPair = ReflectionUtil.getField(ServerIdInjector.minecraftServer, KeyPair.class, 0);
|
||||
|
||||
private final YggdrasilMinecraftSessionService service;
|
||||
private final URL checkUrlBackup;
|
||||
|
||||
private final KeyPair keyPair;
|
||||
private final ServerIdInjector serverIdInjector;
|
||||
private final String altAuthServer;
|
||||
|
||||
public AltAuthSessionService(ServerIdInjector serverIdInjector, String altAuthServer) {
|
||||
this.serverIdInjector = serverIdInjector;
|
||||
this.altAuthServer = altAuthServer;
|
||||
this.keyPair = getKeyPair.get(serverIdInjector.minecraftServerInstance());
|
||||
|
||||
service = swapService.apply(this);
|
||||
checkUrlBackup = CHECK_URL.get(URL_STATIC ? null : service);
|
||||
|
||||
try {
|
||||
CHECK_URL.set(URL_STATIC ? null : service, new URL("https://" + altAuthServer + "/session/minecraft/hasJoined"));
|
||||
} catch (MalformedURLException e) {
|
||||
AltAuthBukkit.getInstance().getLogger().log(Level.SEVERE, "Could not create AltAuth URLs", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void revert() {
|
||||
CHECK_URL.set(URL_STATIC ? null : service, checkUrlBackup);
|
||||
revertService.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinServer(GameProfile gameProfile, String s, String s1) throws AuthenticationException {
|
||||
service.joinServer(gameProfile, s, s1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile hasJoinedServer(GameProfile gameProfile, String serverId, InetAddress inetAddress) throws AuthenticationUnavailableException {
|
||||
return service.hasJoinedServer(gameProfile, new BigInteger((byte[]) getServerHash.invoke(null, altAuthServer, keyPair.getPublic(), getSecretKey.invoke(null, keyPair.getPrivate(), serverIdInjector.getEncryptedSecret(gameProfile.getName())))).toString(16), inetAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getTextures(GameProfile gameProfile, boolean b) {
|
||||
return service.getTextures(gameProfile, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile fillProfileProperties(GameProfile gameProfile, boolean b) {
|
||||
return service.fillProfileProperties(gameProfile, b);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package de.lixfel.altauth.bukkit;
|
||||
|
||||
import de.lixfel.ReflectionUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class EncryptionRequestInjector {
|
||||
|
||||
private static final Class<?> EncryptionRequest = ReflectionUtil.getClass("net.minecraft.network.protocol.login.PacketLoginOutEncryptionBegin");
|
||||
private static final ReflectionUtil.FieldWrapper<String> ServerID = ReflectionUtil.getField(EncryptionRequest, String.class, 0);
|
||||
|
||||
private final String altAuthServer;
|
||||
|
||||
public EncryptionRequestInjector(String altAuthServer) {
|
||||
this.altAuthServer = altAuthServer;
|
||||
|
||||
ProtocolInjector.instance.addFilter(EncryptionRequest, this::handleEncryptionRequest);
|
||||
}
|
||||
|
||||
public Object handleEncryptionRequest(Player player, Object packet) {
|
||||
ServerID.set(packet, altAuthServer);
|
||||
ProtocolInjector.instance.getInterceptor(player).ifPresent(ProtocolInjector.PacketInterceptor::close);
|
||||
return packet;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
ProtocolInjector.instance.removeFilter(EncryptionRequest, this::handleEncryptionRequest);
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package de.lixfel.altauth.bukkit;
|
||||
|
||||
import de.lixfel.ReflectionUtil;
|
||||
import de.lixfel.ReflectionUtil.FieldWrapper;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.logging.Level;
|
||||
|
||||
// ProtocolInjector heavily inspired by TinyProtocol
|
||||
public class ProtocolInjector implements Listener {
|
||||
|
||||
private static final Class<?> craftServer = ReflectionUtil.getClass("org.bukkit.craftbukkit.CraftServer");
|
||||
private static final Class<?> dedicatedPlayerList = ReflectionUtil.getClass("net.minecraft.server.dedicated.DedicatedPlayerList");
|
||||
private static final FieldWrapper<?> getPlayerList = ReflectionUtil.getField(craftServer, dedicatedPlayerList, 0);
|
||||
private static final Class<?> playerList = ReflectionUtil.getClass("net.minecraft.server.players.PlayerList");
|
||||
public static final Class<?> minecraftServer = ReflectionUtil.getClass("net.minecraft.server.MinecraftServer");
|
||||
private static final FieldWrapper<?> getMinecraftServer = ReflectionUtil.getField(playerList, minecraftServer, 0);
|
||||
private static final Class<?> serverConnection = ReflectionUtil.getClass("net.minecraft.server.network.ServerConnection");
|
||||
private static final FieldWrapper<?> getServerConnection = ReflectionUtil.getField(minecraftServer, serverConnection, 0);
|
||||
private static final Class<?> networkManager = ReflectionUtil.getClass("net.minecraft.network.NetworkManager");
|
||||
private static final FieldWrapper<List> getConnections = ReflectionUtil.getField(serverConnection, List.class, 0, networkManager);
|
||||
|
||||
public static final ProtocolInjector instance = new ProtocolInjector(AltAuthBukkit.getInstance());
|
||||
|
||||
public static void init() {
|
||||
//enforce init
|
||||
}
|
||||
|
||||
private final Plugin plugin;
|
||||
private final String handlerName;
|
||||
private final Object minecraftServerInstance;
|
||||
private final List<?> connections;
|
||||
private boolean closed;
|
||||
|
||||
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>();
|
||||
private final Map<Player, PacketInterceptor> playerInterceptors = new HashMap<>();
|
||||
|
||||
private ProtocolInjector(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.handlerName = "altauth";
|
||||
this.minecraftServerInstance = getMinecraftServer.get(getPlayerList.get(plugin.getServer()));
|
||||
this.connections = getConnections.get(getServerConnection.get(minecraftServerInstance));
|
||||
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
new PacketInterceptor(player);
|
||||
}
|
||||
}
|
||||
|
||||
public Object minecraftServer() {
|
||||
return minecraftServerInstance;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent e) {
|
||||
if(closed)
|
||||
return;
|
||||
new PacketInterceptor(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerDisconnect(PlayerQuitEvent e) {
|
||||
getInterceptor(e.getPlayer()).ifPresent(PacketInterceptor::close);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginDisable(PluginDisableEvent e) {
|
||||
if (e.getPlugin().equals(plugin)) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void addFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
|
||||
packetFilters.computeIfAbsent(packetType, c -> new ArrayList<>(1)).add(filter);
|
||||
}
|
||||
|
||||
public void removeFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
|
||||
packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter);
|
||||
}
|
||||
|
||||
public final void close() {
|
||||
if(closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
HandlerList.unregisterAll(this);
|
||||
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
getInterceptor(player).ifPresent(PacketInterceptor::close);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<PacketInterceptor> getInterceptor(Player player) {
|
||||
synchronized (playerInterceptors) {
|
||||
return Optional.ofNullable(playerInterceptors.get(player));
|
||||
}
|
||||
}
|
||||
|
||||
private static final FieldWrapper<Channel> getChannel = ReflectionUtil.getField(networkManager, Channel.class, 0);
|
||||
private static final FieldWrapper<UUID> getUUID = ReflectionUtil.getField(networkManager, UUID.class, 0);
|
||||
|
||||
public final class PacketInterceptor extends ChannelDuplexHandler {
|
||||
private final Player player;
|
||||
private final Channel channel;
|
||||
|
||||
private PacketInterceptor(Player player) {
|
||||
this.player = player;
|
||||
|
||||
channel = getChannel.get(connections.stream().filter(connection -> player.getUniqueId().equals(getUUID.get(connection))).findAny().orElseThrow(() -> new SecurityException("Could not find channel for player " + player.getName())));
|
||||
|
||||
synchronized (playerInterceptors) {
|
||||
playerInterceptors.put(player, this);
|
||||
}
|
||||
|
||||
channel.pipeline().addBefore("packet_handler", handlerName, this);
|
||||
}
|
||||
|
||||
private void sendPacket(Object packet) {
|
||||
channel.pipeline().writeAndFlush(packet);
|
||||
}
|
||||
|
||||
private void receivePacket(Object packet) {
|
||||
channel.pipeline().context("encoder").fireChannelRead(packet);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(channel.isActive()) {
|
||||
channel.eventLoop().execute(() -> {
|
||||
try {
|
||||
channel.pipeline().remove(handlerName);
|
||||
} catch (NoSuchElementException e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
synchronized (playerInterceptors) {
|
||||
playerInterceptors.remove(player, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
try {
|
||||
msg = filterPacket(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error during incoming packet processing", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
try {
|
||||
msg = filterPacket(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error during outgoing packet processing", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
|
||||
private Object filterPacket(Player player, Object packet) {
|
||||
List<BiFunction<Player, Object, Object>> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList());
|
||||
|
||||
for(BiFunction<Player, Object, Object> filter : filters) {
|
||||
packet = filter.apply(player, packet);
|
||||
|
||||
if(packet == null)
|
||||
break;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
}
|
126
bukkit/src/de/lixfel/altauth/bukkit/ServerIdInjector.java
Normale Datei
126
bukkit/src/de/lixfel/altauth/bukkit/ServerIdInjector.java
Normale Datei
@ -0,0 +1,126 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package de.lixfel.altauth.bukkit;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import de.lixfel.ReflectionUtil;
|
||||
import de.lixfel.ReflectionUtil.FieldWrapper;
|
||||
import io.netty.channel.*;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
// ServerIdInjector heavily inspired by TinyProtocol
|
||||
public class ServerIdInjector {
|
||||
|
||||
private static final Class<?> craftServer = ReflectionUtil.getClass("org.bukkit.craftbukkit.CraftServer");
|
||||
private static final Class<?> dedicatedPlayerList = ReflectionUtil.getClass("net.minecraft.server.dedicated.DedicatedPlayerList");
|
||||
private static final FieldWrapper<?> getPlayerList = ReflectionUtil.getField(craftServer, dedicatedPlayerList, 0);
|
||||
private static final Class<?> playerList = ReflectionUtil.getClass("net.minecraft.server.players.PlayerList");
|
||||
public static final Class<?> minecraftServer = ReflectionUtil.getClass("net.minecraft.server.MinecraftServer");
|
||||
private static final FieldWrapper<?> getMinecraftServer = ReflectionUtil.getField(playerList, minecraftServer, 0);
|
||||
private static final Class<?> serverConnection = ReflectionUtil.getClass("net.minecraft.server.network.ServerConnection");
|
||||
private static final FieldWrapper<?> getServerConnection = ReflectionUtil.getField(minecraftServer, serverConnection, 0);
|
||||
private static final FieldWrapper<List> getChannelFutures = ReflectionUtil.getField(serverConnection, List.class, 0, ChannelFuture.class);
|
||||
|
||||
private static final Class networkManager = ReflectionUtil.getClass("net.minecraft.network.NetworkManager");
|
||||
private static final Class<?> packetListener = ReflectionUtil.getClass("net.minecraft.network.PacketListener");
|
||||
private static final FieldWrapper<?> getPacketListener = ReflectionUtil.getField(networkManager, packetListener, 0);
|
||||
|
||||
public static final Class<?> loginListener = ReflectionUtil.getClass("net.minecraft.server.network.LoginListener");
|
||||
private static final FieldWrapper<GameProfile> getGameProfile = ReflectionUtil.getField(loginListener, GameProfile.class, 0);
|
||||
|
||||
private static final Class<?> packetLoginInEncryptionBegin = ReflectionUtil.getClass("net.minecraft.network.protocol.login.PacketLoginInEncryptionBegin");
|
||||
private static final FieldWrapper<byte[]> getEncryptedSecret = ReflectionUtil.getField(packetLoginInEncryptionBegin, byte[].class, 0);
|
||||
private static final Class<?> packetLoginOutEncryptionBegin = ReflectionUtil.getClass("net.minecraft.network.protocol.login.PacketLoginOutEncryptionBegin");
|
||||
private static final FieldWrapper<String> getPacketServerID = ReflectionUtil.getField(packetLoginOutEncryptionBegin, String.class, 0);
|
||||
|
||||
private final String altAuthServer;
|
||||
private final String handlerName;
|
||||
private final String initializerName;
|
||||
private final Object minecraftServerInstance;
|
||||
private final List<ChannelFuture> channelFutures;
|
||||
|
||||
private final Map<String, byte[]> encryptedSecrets = new ConcurrentHashMap<>();
|
||||
|
||||
private boolean closed;
|
||||
|
||||
private final ChannelInitializer<Channel> initializer = new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
protected void initChannel(Channel channel) {
|
||||
if(!closed)
|
||||
new PacketInterceptor(channel);
|
||||
}
|
||||
};
|
||||
|
||||
public ServerIdInjector(Plugin plugin, String altAuthServer) {
|
||||
this.altAuthServer = altAuthServer;
|
||||
this.handlerName = "altauth";
|
||||
this.initializerName = "altauth-init";
|
||||
this.minecraftServerInstance = getMinecraftServer.get(getPlayerList.get(plugin.getServer()));
|
||||
this.channelFutures = getChannelFutures.get(getServerConnection.get(minecraftServerInstance));
|
||||
|
||||
for(ChannelFuture serverChannel : channelFutures) {
|
||||
serverChannel.channel().pipeline().addFirst(initializerName, new ChannelInboundHandlerAdapter() {
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object o) throws Exception {
|
||||
super.channelRead(ctx, o);
|
||||
|
||||
Channel channel = (Channel) o;
|
||||
channel.pipeline().addLast(initializerName, initializer);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Object minecraftServerInstance() {
|
||||
return minecraftServerInstance;
|
||||
}
|
||||
|
||||
public byte[] getEncryptedSecret(String name) {
|
||||
return encryptedSecrets.remove(name);
|
||||
}
|
||||
|
||||
public final void close() {
|
||||
if(closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
for(ChannelFuture serverChannel : channelFutures) {
|
||||
serverChannel.channel().pipeline().remove(initializerName);
|
||||
}
|
||||
}
|
||||
|
||||
public final class PacketInterceptor extends ChannelDuplexHandler {
|
||||
private final Channel channel;
|
||||
|
||||
private PacketInterceptor(Channel channel) {
|
||||
this.channel = channel;
|
||||
channel.pipeline().addBefore("packet_handler", handlerName, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
|
||||
if(packetLoginInEncryptionBegin.isInstance(packet)) {
|
||||
encryptedSecrets.put(
|
||||
getGameProfile.get(getPacketListener.get(channel.pipeline().get(networkManager))).getName(),
|
||||
getEncryptedSecret.get(packet)
|
||||
);
|
||||
channel.pipeline().remove(this);
|
||||
}
|
||||
|
||||
super.channelRead(ctx, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
||||
if(packetLoginOutEncryptionBegin.isInstance(packet)) {
|
||||
getPacketServerID.set(packet, altAuthServer);
|
||||
}
|
||||
|
||||
super.write(ctx, packet, promise);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package de.lixfel.altauth.bukkit;
|
||||
|
||||
import de.lixfel.ReflectionUtil;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SessionServiceInjector {
|
||||
|
||||
private static final Class<?> MINECRAFT_SESSION_SERVICE = ReflectionUtil.getClass("com.mojang.authlib.minecraft.MinecraftSessionService");
|
||||
private static final Class<?> YGGDRASIL_SESSION_SERVICE = ReflectionUtil.getClass("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService");
|
||||
|
||||
private static final ReflectionUtil.FieldWrapper<URL> JOIN_URL = ReflectionUtil.getField(YGGDRASIL_SESSION_SERVICE, URL.class, 0);
|
||||
private static final ReflectionUtil.FieldWrapper<URL> CHECK_URL = ReflectionUtil.getField(YGGDRASIL_SESSION_SERVICE, URL.class, 1);
|
||||
|
||||
private final Object sessionService;
|
||||
private final URL joinUrlBackup;
|
||||
private final URL checkUrlBackup;
|
||||
|
||||
public SessionServiceInjector(String altAuthServer) {
|
||||
altAuthServer = "https://" + altAuthServer + "/session/minecraft/";
|
||||
|
||||
if(ReflectionUtil.MINECRAFT_VERSION < 17) { //TODO maybe 16 (untested)
|
||||
sessionService = null;
|
||||
} else if (ReflectionUtil.MINECRAFT_VERSION < 19) {
|
||||
sessionService = ReflectionUtil.getField(ProtocolInjector.minecraftServer, MINECRAFT_SESSION_SERVICE, 0).get(
|
||||
ProtocolInjector.instance.minecraftServer()
|
||||
);
|
||||
} else {
|
||||
Class<?> services = ReflectionUtil.getClass("net.minecraft.server.Services");
|
||||
sessionService = ReflectionUtil.getField(services, MINECRAFT_SESSION_SERVICE, 0).get(
|
||||
ReflectionUtil.getField(ProtocolInjector.minecraftServer, services, 0).get(
|
||||
ProtocolInjector.instance.minecraftServer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
joinUrlBackup = JOIN_URL.get(sessionService);
|
||||
checkUrlBackup = CHECK_URL.get(sessionService);
|
||||
|
||||
try {
|
||||
JOIN_URL.set(sessionService, new URL(altAuthServer + "join"));
|
||||
CHECK_URL.set(sessionService, new URL(altAuthServer + "hasJoined"));
|
||||
} catch (MalformedURLException e) {
|
||||
AltAuthBukkit.getInstance().getLogger().log(Level.SEVERE, "Could not create AltAuth URLs", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void revert() {
|
||||
JOIN_URL.set(sessionService, joinUrlBackup);
|
||||
CHECK_URL.set(sessionService, checkUrlBackup);
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren