Search in sources :

Example 1 with NetworkSession

use of org.lanternpowered.server.network.NetworkSession in project LanternServer by LanternPowered.

the class HandlerHandshakeIn method handle.

@Override
public void handle(NetworkContext context, MessageHandshakeIn message) {
    final Optional<ProtocolState> optNextState = ProtocolState.getFromId(message.getNextState());
    final NetworkSession session = context.getSession();
    if (!optNextState.isPresent()) {
        session.disconnect(t("Unknown protocol state! (%s)", message.getNextState()));
        return;
    }
    final ProtocolState nextState = optNextState.get();
    session.setProtocolState(nextState);
    if (!nextState.equals(ProtocolState.LOGIN) && !nextState.equals(ProtocolState.STATUS)) {
        session.disconnect(t("Received a unexpected handshake message! (%s)", nextState));
        return;
    }
    final ProxyType proxyType = Lantern.getGame().getGlobalConfig().getProxyType();
    String hostname = message.getHostname();
    InetSocketAddress virtualAddress;
    switch(proxyType) {
        case WATERFALL:
        case BUNGEE_CORD:
            String[] split = hostname.split("\0\\|", 2);
            // Check for a fml marker
            session.getChannel().attr(NetworkSession.FML_MARKER).set(split.length == 2 == split[1].contains(FML_MARKER));
            split = split[0].split("\00");
            if (split.length == 3 || split.length == 4) {
                virtualAddress = new InetSocketAddress(split[1], message.getPort());
                final UUID uniqueId = UUIDHelper.fromFlatString(split[2]);
                final Multimap<String, ProfileProperty> properties;
                if (split.length == 4) {
                    try {
                        properties = LanternProfileProperty.createPropertiesMapFromJson(GSON.fromJson(split[3], JsonArray.class));
                    } catch (Exception e) {
                        session.disconnect(t("Invalid %s proxy data format.", proxyType.getName()));
                        throw new CodecException(e);
                    }
                } else {
                    properties = LinkedHashMultimap.create();
                }
                session.getChannel().attr(HandlerLoginStart.SPOOFED_GAME_PROFILE).set(new LanternGameProfile(uniqueId, null, properties));
            } else {
                session.disconnect(t("Please enable client detail forwarding (also known as \"ip forwarding\") on " + "your proxy if you wish to use it on this server, and also make sure that you joined through the proxy."));
                return;
            }
            break;
        case LILY_PAD:
            try {
                final JsonObject jsonObject = GSON.fromJson(hostname, JsonObject.class);
                final String securityKey = Lantern.getGame().getGlobalConfig().getProxySecurityKey();
                // Validate the security key
                if (!securityKey.isEmpty() && !jsonObject.get("s").getAsString().equals(securityKey)) {
                    session.disconnect(t("Proxy security key mismatch"));
                    Lantern.getLogger().warn("Proxy security key mismatch for the player {}", jsonObject.get("n").getAsString());
                    return;
                }
                final String name = jsonObject.get("n").getAsString();
                final UUID uniqueId = UUIDHelper.fromFlatString(jsonObject.get("u").getAsString());
                final Multimap<String, ProfileProperty> properties = LinkedHashMultimap.create();
                if (jsonObject.has("p")) {
                    final JsonArray jsonArray = jsonObject.getAsJsonArray("p");
                    for (int i = 0; i < jsonArray.size(); i++) {
                        final JsonObject property = jsonArray.get(i).getAsJsonObject();
                        final String propertyName = property.get("n").getAsString();
                        final String propertyValue = property.get("v").getAsString();
                        final String propertySignature = property.has("s") ? property.get("s").getAsString() : null;
                        properties.put(propertyName, new LanternProfileProperty(propertyName, propertyValue, propertySignature));
                    }
                }
                session.getChannel().attr(HandlerLoginStart.SPOOFED_GAME_PROFILE).set(new LanternGameProfile(uniqueId, name, properties));
                session.getChannel().attr(NetworkSession.FML_MARKER).set(false);
                final int port = jsonObject.get("rP").getAsInt();
                final String host = jsonObject.get("h").getAsString();
                virtualAddress = new InetSocketAddress(host, port);
            } catch (Exception e) {
                session.disconnect(t("Invalid %s proxy data format.", proxyType.getName()));
                throw new CodecException(e);
            }
            break;
        case NONE:
            int index = hostname.indexOf(FML_MARKER);
            session.getChannel().attr(NetworkSession.FML_MARKER).set(index != -1);
            if (index != -1) {
                hostname = hostname.substring(0, index);
            }
            virtualAddress = new InetSocketAddress(hostname, message.getPort());
            break;
        default:
            throw new IllegalStateException("The proxy type " + proxyType + " isn't implemented");
    }
    session.setVirtualHost(virtualAddress);
    session.setProtocolVersion(message.getProtocolVersion());
    if (nextState == ProtocolState.LOGIN) {
        final int protocol = Lantern.getGame().getPlatform().getMinecraftVersion().getProtocol();
        if (message.getProtocolVersion() < protocol) {
            session.disconnect(t("multiplayer.disconnect.outdated_client", Lantern.getGame().getPlatform().getMinecraftVersion().getName()));
        } else if (message.getProtocolVersion() > protocol) {
            session.disconnect(t("multiplayer.disconnect.outdated_server", Lantern.getGame().getPlatform().getMinecraftVersion().getName()));
        }
    }
}
Also used : NetworkSession(org.lanternpowered.server.network.NetworkSession) ProfileProperty(org.spongepowered.api.profile.property.ProfileProperty) LanternProfileProperty(org.lanternpowered.server.profile.LanternProfileProperty) InetSocketAddress(java.net.InetSocketAddress) LanternGameProfile(org.lanternpowered.server.profile.LanternGameProfile) JsonObject(com.google.gson.JsonObject) CodecException(io.netty.handler.codec.CodecException) JsonArray(com.google.gson.JsonArray) CodecException(io.netty.handler.codec.CodecException) ProxyType(org.lanternpowered.server.network.ProxyType) ProtocolState(org.lanternpowered.server.network.protocol.ProtocolState) UUID(java.util.UUID) LanternProfileProperty(org.lanternpowered.server.profile.LanternProfileProperty)

Example 2 with NetworkSession

use of org.lanternpowered.server.network.NetworkSession in project LanternServer by LanternPowered.

the class HandlerPlayInChatMessage method handle.

@Override
public void handle(NetworkContext context, MessagePlayInChatMessage message) {
    final NetworkSession session = context.getSession();
    final LanternPlayer player = session.getPlayer();
    player.resetIdleTimeoutCounter();
    final String message0 = message.getMessage();
    // Check for a valid click action callback
    final Matcher matcher = LanternClickActionCallbacks.COMMAND_PATTERN.matcher(message0);
    if (matcher.matches()) {
        final UUID uniqueId = UUID.fromString(matcher.group(1));
        final Optional<Consumer<CommandSource>> callback = LanternClickActionCallbacks.get().getCallbackForUUID(uniqueId);
        if (callback.isPresent()) {
            callback.get().accept(player);
        } else {
            player.sendMessage(error(t("The callback you provided was not valid. Keep in mind that callbacks will expire " + "after 10 minutes, so you might want to consider clicking faster next time!")));
        }
        return;
    }
    String message1 = StringUtils.normalizeSpace(message0);
    if (!isAllowedString(message0)) {
        session.disconnect(t("multiplayer.disconnect.illegal_characters"));
        return;
    }
    if (message1.startsWith("/")) {
        Lantern.getSyncExecutorService().submit(() -> Sponge.getCommandManager().process(player, message1.substring(1)));
    } else {
        final Text nameText = player.get(Keys.DISPLAY_NAME).get();
        final Text rawMessageText = Text.of(message0);
        final GlobalConfig.Chat.Urls urls = Lantern.getGame().getGlobalConfig().getChat().getUrls();
        final Text messageText;
        if (urls.isEnabled() && player.hasPermission(Permissions.Chat.FORMAT_URLS)) {
            messageText = newTextWithLinks(message0, urls.getTemplate(), false);
        } else {
            messageText = rawMessageText;
        }
        final MessageChannel channel = player.getMessageChannel();
        final CauseStack causeStack = CauseStack.current();
        try (CauseStack.Frame frame = causeStack.pushCauseFrame()) {
            frame.addContext(EventContextKeys.PLAYER, player);
            final MessageChannelEvent.Chat event = SpongeEventFactory.createMessageChannelEventChat(causeStack.getCurrentCause(), channel, Optional.of(channel), new MessageEvent.MessageFormatter(nameText, messageText), rawMessageText, false);
            if (!Sponge.getEventManager().post(event) && !event.isMessageCancelled()) {
                event.getChannel().ifPresent(c -> c.send(player, event.getMessage(), ChatTypes.CHAT));
            }
        }
    }
    final Attribute<ChatData> attr = context.getChannel().attr(CHAT_DATA);
    ChatData chatData = attr.get();
    if (chatData == null) {
        chatData = new ChatData();
        final ChatData chatData1 = attr.setIfAbsent(chatData);
        if (chatData1 != null) {
            chatData = chatData1;
        }
    }
    // noinspection SynchronizationOnLocalVariableOrMethodParameter
    synchronized (chatData) {
        final long currentTime = LanternGame.currentTimeTicks();
        if (chatData.lastChatTime != -1L) {
            chatData.chatThrottle = (int) Math.max(0, chatData.chatThrottle - (currentTime - chatData.lastChatTime));
        }
        chatData.lastChatTime = currentTime;
        chatData.chatThrottle += 20;
        if (chatData.chatThrottle > Lantern.getGame().getGlobalConfig().getChatSpamThreshold()) {
            session.disconnect(t("disconnect.spam"));
        }
    }
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack) NetworkSession(org.lanternpowered.server.network.NetworkSession) Matcher(java.util.regex.Matcher) MessageChannelEvent(org.spongepowered.api.event.message.MessageChannelEvent) MessageEvent(org.spongepowered.api.event.message.MessageEvent) Text(org.spongepowered.api.text.Text) Consumer(java.util.function.Consumer) MessageChannel(org.spongepowered.api.text.channel.MessageChannel) UUID(java.util.UUID) LanternPlayer(org.lanternpowered.server.entity.living.player.LanternPlayer)

Example 3 with NetworkSession

use of org.lanternpowered.server.network.NetworkSession in project LanternServer by LanternPowered.

the class HandlerForgeHandshakeInAck method handle.

@Override
public void handle(NetworkContext context, MessageForgeHandshakeInOutAck message) {
    final NetworkSession session = context.getSession();
    final Attribute<ForgeServerHandshakePhase> phase = context.getChannel().attr(ForgeHandshakePhase.PHASE);
    switch(phase.get()) {
        case WAITING_ACK:
            if (!message.getPhase().equals(ForgeClientHandshakePhase.WAITING_SERVER_DATA)) {
                session.disconnect(t("Retrieved unexpected forge handshake ack message. (Got %s, expected %s)", message.getPhase(), ForgeClientHandshakePhase.WAITING_SERVER_DATA));
            } else {
                final List<MessageForgeHandshakeOutRegistryData.Entry> entries = new ArrayList<>();
                entries.add(new MessageForgeHandshakeOutRegistryData.Entry("minecraft:items", new HashMap<>(), new ArrayList<>()));
                entries.add(new MessageForgeHandshakeOutRegistryData.Entry("minecraft:blocks", new HashMap<>(), new ArrayList<>()));
                session.send(new MessageForgeHandshakeOutRegistryData(entries));
                session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.WAITING_ACK));
                phase.set(ForgeServerHandshakePhase.COMPLETE);
            }
            Lantern.getLogger().info("{}: Forge handshake -> Received ack (waitingServerData) message.", session.getGameProfile().getName().get());
            break;
        case COMPLETE:
            if (!message.getPhase().equals(ForgeClientHandshakePhase.WAITING_SERVER_COMPLETE)) {
                session.disconnect(t("Retrieved unexpected forge handshake ack message. (Got %s, expected %s)", message.getPhase(), ForgeClientHandshakePhase.WAITING_SERVER_COMPLETE));
            } else {
                session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.COMPLETE));
                phase.set(ForgeServerHandshakePhase.DONE);
            }
            Lantern.getLogger().info("{}: Forge handshake -> Received ack (waitingServerComplete) message.", session.getGameProfile().getName().get());
            break;
        case DONE:
            if (!message.getPhase().equals(ForgeClientHandshakePhase.PENDING_COMPLETE) && !message.getPhase().equals(ForgeClientHandshakePhase.COMPLETE)) {
                session.disconnect(t("Retrieved unexpected forge handshake ack message. (Got %s, expected %s or %s)", message.getPhase(), ForgeClientHandshakePhase.PENDING_COMPLETE, ForgeClientHandshakePhase.COMPLETE));
            } else {
                if (message.getPhase().equals(ForgeClientHandshakePhase.PENDING_COMPLETE)) {
                    session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.DONE));
                    Lantern.getLogger().info("{}: Forge handshake -> Received ack (pendingComplete) message.", session.getGameProfile().getName().get());
                } else {
                    session.setProtocolState(ProtocolState.PLAY);
                    session.initPlayer();
                    Lantern.getLogger().info("{}: Forge handshake -> Received ack (complete) message.", session.getGameProfile().getName().get());
                }
            }
            break;
        case ERROR:
            break;
        default:
            session.disconnect(t("Retrieved unexpected forge handshake ack message. (Got %s)", message.getPhase()));
    }
}
Also used : ForgeServerHandshakePhase(org.lanternpowered.server.network.forge.handshake.ForgeServerHandshakePhase) NetworkSession(org.lanternpowered.server.network.NetworkSession) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) MessageForgeHandshakeOutRegistryData(org.lanternpowered.server.network.forge.message.type.handshake.MessageForgeHandshakeOutRegistryData) MessageForgeHandshakeInOutAck(org.lanternpowered.server.network.forge.message.type.handshake.MessageForgeHandshakeInOutAck)

Example 4 with NetworkSession

use of org.lanternpowered.server.network.NetworkSession in project LanternServer by LanternPowered.

the class HandlerForgeHandshakeInHello method handle.

@Override
public void handle(NetworkContext context, MessageForgeHandshakeInOutHello message) {
    final NetworkSession session = context.getSession();
    final Attribute<ForgeServerHandshakePhase> phase = session.getChannel().attr(ForgeHandshakePhase.PHASE);
    if (phase.get() != ForgeServerHandshakePhase.HELLO) {
        session.disconnect(t("Retrieved unexpected forge handshake hello message."));
        return;
    }
    Lantern.getLogger().info("{}: Forge handshake -> Received hello message.", session.getGameProfile().getName().get());
}
Also used : ForgeServerHandshakePhase(org.lanternpowered.server.network.forge.handshake.ForgeServerHandshakePhase) NetworkSession(org.lanternpowered.server.network.NetworkSession)

Example 5 with NetworkSession

use of org.lanternpowered.server.network.NetworkSession in project LanternServer by LanternPowered.

the class HandlerForgeHandshakeInStart method handle.

@Override
public void handle(NetworkContext context, MessageForgeHandshakeInStart message) {
    final Attribute<ForgeServerHandshakePhase> phase = context.getChannel().attr(ForgeHandshakePhase.PHASE);
    final NetworkSession session = context.getSession();
    if (phase.get() != null && phase.get() != ForgeServerHandshakePhase.START) {
        session.disconnect(t("Retrieved unexpected forge handshake start message."));
        return;
    }
    final boolean fml = session.getChannel().attr(NetworkSession.FML_MARKER).get();
    final Set<String> channels = new HashSet<>(Sponge.getChannelRegistrar().getRegisteredChannels(Platform.Type.SERVER));
    if (fml) {
        channels.add("FML");
        channels.add("FML|HS");
        channels.add("FML|MP");
    }
    if (!channels.isEmpty()) {
        session.send(new MessagePlayInOutRegisterChannels(channels));
    }
    // future if sponge uses completely it's own protocol.
    if (false && fml) {
        phase.set(ForgeServerHandshakePhase.HELLO);
        session.send(new MessageForgeHandshakeInOutHello());
        Lantern.getLogger().info("{}: Start forge handshake.", session.getGameProfile().getName().get());
    } else {
        Lantern.getLogger().info("{}: Skip forge handshake.", session.getGameProfile().getName().get());
        phase.set(ForgeServerHandshakePhase.DONE);
        session.setProtocolState(ProtocolState.PLAY);
        session.initPlayer();
    }
}
Also used : MessageForgeHandshakeInOutHello(org.lanternpowered.server.network.forge.message.type.handshake.MessageForgeHandshakeInOutHello) ForgeServerHandshakePhase(org.lanternpowered.server.network.forge.handshake.ForgeServerHandshakePhase) MessagePlayInOutRegisterChannels(org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutRegisterChannels) NetworkSession(org.lanternpowered.server.network.NetworkSession) HashSet(java.util.HashSet)

Aggregations

NetworkSession (org.lanternpowered.server.network.NetworkSession)14 LanternPlayer (org.lanternpowered.server.entity.living.player.LanternPlayer)4 ForgeServerHandshakePhase (org.lanternpowered.server.network.forge.handshake.ForgeServerHandshakePhase)4 UUID (java.util.UUID)3 LanternGameProfile (org.lanternpowered.server.profile.LanternGameProfile)3 JsonArray (com.google.gson.JsonArray)2 JsonObject (com.google.gson.JsonObject)2 InetSocketAddress (java.net.InetSocketAddress)2 HashMap (java.util.HashMap)2 MessagePlayInOutRegisterChannels (org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutRegisterChannels)2 Player (org.spongepowered.api.entity.living.player.Player)2 Text (org.spongepowered.api.text.Text)2 Gson (com.google.gson.Gson)1 CodecException (io.netty.handler.codec.CodecException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 BigInteger (java.math.BigInteger)1 InetAddress (java.net.InetAddress)1 SocketException (java.net.SocketException)1 GeneralSecurityException (java.security.GeneralSecurityException)1 MessageDigest (java.security.MessageDigest)1