Search in sources :

Example 6 with NetworkSession

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

the class LanternChannelRegistrar method create.

private LanternChannelBinding create(Object plugin, String channel, boolean rawChannel) throws ChannelRegistrationException {
    final PluginContainer container = checkPlugin(plugin, "plugin");
    checkNotNullOrEmpty(channel, "channel");
    checkArgument(channel.length() <= MAX_NAME_LENGTH, "channel length may not be longer then 20");
    if (!isChannelAvailable(channel)) {
        throw new ChannelRegistrationException("Channel with name \"" + channel + "\" is already registered!");
    }
    final LanternChannelBinding binding;
    if (rawChannel) {
        binding = new LanternRawDataChannel(this, channel, container);
    } else {
        binding = new LanternIndexedMessageChannel(this, channel, container);
    }
    binding.bound = true;
    final MessagePlayInOutRegisterChannels message = new MessagePlayInOutRegisterChannels(Sets.newHashSet(channel));
    for (Player player : this.server.getOnlinePlayers()) {
        ((NetworkSession) player.getConnection()).send(message);
    }
    return binding;
}
Also used : MessagePlayInOutRegisterChannels(org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutRegisterChannels) LanternPlayer(org.lanternpowered.server.entity.living.player.LanternPlayer) Player(org.spongepowered.api.entity.living.player.Player) PluginContainer(org.spongepowered.api.plugin.PluginContainer) NetworkSession(org.lanternpowered.server.network.NetworkSession) ChannelRegistrationException(org.spongepowered.api.network.ChannelRegistrationException)

Example 7 with NetworkSession

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

the class HandlerStatusRequest method handle.

@Override
public void handle(NetworkContext context, MessageStatusInRequest message) {
    final NetworkSession session = context.getSession();
    final LanternServer server = session.getServer();
    final Gson gson = new Gson();
    final Text description = server.getMotd();
    final InetSocketAddress address = session.getAddress();
    final InetSocketAddress virtualAddress = session.getVirtualHost();
    final int protocol = session.getProtocolVersion();
    final MinecraftVersion clientVersion = Lantern.getGame().getMinecraftVersionCache().getVersionOrUnknown(protocol, false);
    if (clientVersion == LanternMinecraftVersion.UNKNOWN) {
        Lantern.getLogger().debug("Client with unknown protocol version {} pinged the server.", protocol);
    }
    final LanternStatusClient client = new LanternStatusClient(address, clientVersion, virtualAddress);
    final ClientPingServerEvent.Response.Players players = LanternStatusHelper.createPlayers(server);
    final LanternStatusResponse response = new LanternStatusResponse(Lantern.getGame().getPlatform().getMinecraftVersion(), server.getFavicon(), description, players);
    final Cause cause = Cause.of(EventContext.empty(), new WrappedRemoteConnection(session));
    final ClientPingServerEvent event = SpongeEventFactory.createClientPingServerEvent(cause, client, response);
    Sponge.getEventManager().post(event);
    // Cancelled, we are done here
    if (event.isCancelled()) {
        context.getChannel().close();
        return;
    }
    final JsonObject rootObject = new JsonObject();
    final JsonObject versionObject = new JsonObject();
    checkState(response.getVersion() instanceof LanternMinecraftVersion);
    final LanternMinecraftVersion serverVersion = (LanternMinecraftVersion) response.getVersion();
    versionObject.addProperty("name", serverVersion.getName());
    versionObject.addProperty("protocol", serverVersion.getProtocol());
    if (response.getPlayers().isPresent()) {
        final JsonObject playersObject = new JsonObject();
        playersObject.addProperty("max", players.getMax());
        playersObject.addProperty("online", players.getOnline());
        List<GameProfile> profiles = players.getProfiles();
        if (!profiles.isEmpty()) {
            final JsonArray array = new JsonArray();
            for (GameProfile profile : profiles) {
                Optional<String> optName = profile.getName();
                if (!optName.isPresent()) {
                    continue;
                }
                final JsonObject profileObject = new JsonObject();
                profileObject.addProperty("name", optName.get());
                profileObject.addProperty("id", profile.getUniqueId().toString());
                array.add(profileObject);
            }
            playersObject.add("sample", array);
        }
        rootObject.add("players", playersObject);
    }
    rootObject.add("version", versionObject);
    rootObject.add("description", ((LanternJsonTextSerializer) TextSerializers.JSON).getGson().toJsonTree(response.getDescription()));
    response.getFavicon().ifPresent(icon -> rootObject.addProperty("favicon", ((LanternFavicon) icon).getEncoded()));
    final JsonObject fmlObject = new JsonObject();
    // Trick the client that the server is fml, we support fml channels anyway
    fmlObject.addProperty("type", "FML");
    // The client shouldn't know the plugins (mods) list
    fmlObject.add("modList", new JsonArray());
    // Add the fml info
    rootObject.add("modinfo", fmlObject);
    session.send(new MessageStatusOutResponse(gson.toJson(rootObject)));
}
Also used : NetworkSession(org.lanternpowered.server.network.NetworkSession) MessageStatusOutResponse(org.lanternpowered.server.network.vanilla.message.type.status.MessageStatusOutResponse) LanternMinecraftVersion(org.lanternpowered.server.game.version.LanternMinecraftVersion) InetSocketAddress(java.net.InetSocketAddress) Gson(com.google.gson.Gson) JsonObject(com.google.gson.JsonObject) Text(org.spongepowered.api.text.Text) LanternJsonTextSerializer(org.lanternpowered.server.text.gson.LanternJsonTextSerializer) LanternStatusResponse(org.lanternpowered.server.network.status.LanternStatusResponse) MessageStatusOutResponse(org.lanternpowered.server.network.vanilla.message.type.status.MessageStatusOutResponse) JsonArray(com.google.gson.JsonArray) LanternStatusClient(org.lanternpowered.server.network.status.LanternStatusClient) ClientPingServerEvent(org.spongepowered.api.event.server.ClientPingServerEvent) LanternServer(org.lanternpowered.server.LanternServer) GameProfile(org.spongepowered.api.profile.GameProfile) Cause(org.spongepowered.api.event.cause.Cause) LanternFavicon(org.lanternpowered.server.network.status.LanternFavicon) LanternStatusResponse(org.lanternpowered.server.network.status.LanternStatusResponse) LanternMinecraftVersion(org.lanternpowered.server.game.version.LanternMinecraftVersion) MinecraftVersion(org.spongepowered.api.MinecraftVersion) WrappedRemoteConnection(org.lanternpowered.server.network.WrappedRemoteConnection)

Example 8 with NetworkSession

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

the class HandlerEncryptionResponse method handle.

@Override
public void handle(NetworkContext context, MessageLoginInEncryptionResponse message) {
    final NetworkSession session = context.getSession();
    final PrivateKey privateKey = session.getServer().getKeyPair().getPrivate();
    // Create rsaCipher
    Cipher rsaCipher;
    try {
        rsaCipher = Cipher.getInstance("RSA");
    } catch (GeneralSecurityException e) {
        Lantern.getLogger().error("Could not initialize RSA cipher", e);
        session.disconnect(t("Unable to initialize RSA cipher."));
        return;
    }
    // Decrypt shared secret
    SecretKey sharedSecret;
    try {
        rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
        sharedSecret = new SecretKeySpec(rsaCipher.doFinal(message.getSharedSecret()), "AES");
    } catch (Exception e) {
        Lantern.getLogger().warn("Could not decrypt shared secret", e);
        session.disconnect(t("Unable to decrypt shared secret."));
        return;
    }
    // Decrypt verify token
    byte[] verifyToken;
    try {
        rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
        verifyToken = rsaCipher.doFinal(message.getVerifyToken());
    } catch (Exception e) {
        Lantern.getLogger().warn("Could not decrypt verify token", e);
        session.disconnect(t("Unable to decrypt verify token."));
        return;
    }
    LoginAuthData authData = context.getChannel().attr(HandlerLoginStart.AUTH_DATA).getAndSet(null);
    // Check verify token
    if (!Arrays.equals(verifyToken, authData.getVerifyToken())) {
        session.disconnect(t("Invalid verify token."));
        return;
    }
    // Initialize stream encryption
    session.getChannel().pipeline().replace(NetworkSession.ENCRYPTION, NetworkSession.ENCRYPTION, new MessageEncryptionHandler(sharedSecret));
    // Create hash for auth
    String hash;
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        digest.update(authData.getSessionId().getBytes());
        digest.update(sharedSecret.getEncoded());
        digest.update(session.getServer().getKeyPair().getPublic().getEncoded());
        // BigInteger takes care of sign and leading zeroes
        hash = new BigInteger(digest.digest()).toString(16);
    } catch (NoSuchAlgorithmException e) {
        Lantern.getLogger().error("Unable to generate SHA-1 digest", e);
        session.disconnect(t("Failed to hash login data."));
        return;
    }
    String preventProxiesIp = null;
    if (Lantern.getGame().getGlobalConfig().shouldPreventProxyConnections()) {
        final InetAddress address = context.getSession().getAddress().getAddress();
        if (!isLocalAddress(address)) {
            // Ignore local addresses, they will always fail
            try {
                preventProxiesIp = URLEncoder.encode(address.getHostAddress(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                Lantern.getLogger().error("Failed to encode the ip address to prevent proxies.", e);
                session.disconnect(t("Something funky happened."));
                return;
            }
        }
    }
    final String preventProxiesIp1 = preventProxiesIp;
    Lantern.getScheduler().submitAsyncTask(() -> performAuth(session, authData.getUsername(), hash, preventProxiesIp1));
}
Also used : NetworkSession(org.lanternpowered.server.network.NetworkSession) PrivateKey(java.security.PrivateKey) GeneralSecurityException(java.security.GeneralSecurityException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) MessageEncryptionHandler(org.lanternpowered.server.network.pipeline.MessageEncryptionHandler) SocketException(java.net.SocketException) GeneralSecurityException(java.security.GeneralSecurityException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) SecretKey(javax.crypto.SecretKey) SecretKeySpec(javax.crypto.spec.SecretKeySpec) BigInteger(java.math.BigInteger) Cipher(javax.crypto.Cipher) MessageDigest(java.security.MessageDigest) InetAddress(java.net.InetAddress)

Example 9 with NetworkSession

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

the class HandlerLoginFinish method handle.

@Override
public void handle(NetworkContext context, MessageLoginInFinish message) {
    final LanternGameProfile gameProfile = message.getGameProfile();
    final NetworkSession session = context.getSession();
    int compressionThreshold = Lantern.getGame().getGlobalConfig().getNetworkCompressionThreshold();
    if (compressionThreshold != -1) {
        session.sendWithFuture(new MessageLoginOutSetCompression(compressionThreshold)).addListener(future -> context.getChannel().pipeline().replace(NetworkSession.COMPRESSION, NetworkSession.COMPRESSION, new MessageCompressionHandler(compressionThreshold)));
    } else {
        // Remove the compression handler placeholder
        context.getChannel().pipeline().remove(NetworkSession.COMPRESSION);
    }
    final GameProfileCache gameProfileCache = Lantern.getGame().getGameProfileManager().getCache();
    // Store the old profile temporarily
    gameProfileCache.getById(gameProfile.getUniqueId()).ifPresent(profile -> context.getChannel().attr(NetworkSession.PREVIOUS_GAME_PROFILE).set(profile));
    // Cache the new profile
    gameProfileCache.add(gameProfile, true, (Instant) null);
    session.sendWithFuture(new MessageLoginOutSuccess(gameProfile.getUniqueId(), gameProfile.getName().get())).addListener(future -> {
        session.setGameProfile(gameProfile);
        session.setProtocolState(ProtocolState.FORGE_HANDSHAKE);
        session.messageReceived(new MessageForgeHandshakeInStart());
    });
}
Also used : MessageCompressionHandler(org.lanternpowered.server.network.pipeline.MessageCompressionHandler) MessageForgeHandshakeInStart(org.lanternpowered.server.network.forge.message.type.handshake.MessageForgeHandshakeInStart) NetworkSession(org.lanternpowered.server.network.NetworkSession) LanternGameProfile(org.lanternpowered.server.profile.LanternGameProfile) GameProfileCache(org.spongepowered.api.profile.GameProfileCache) MessageLoginOutSetCompression(org.lanternpowered.server.network.vanilla.message.type.login.MessageLoginOutSetCompression) MessageLoginOutSuccess(org.lanternpowered.server.network.vanilla.message.type.login.MessageLoginOutSuccess)

Example 10 with NetworkSession

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

the class HandlerLoginStart method handle.

@Override
public void handle(NetworkContext context, MessageLoginInStart message) {
    final NetworkSession session = context.getSession();
    final String username = message.getUsername();
    if (session.getServer().getOnlineMode()) {
        // Convert to X509 format
        final byte[] publicKey = SecurityHelper.generateX509Key(session.getServer().getKeyPair().getPublic()).getEncoded();
        final byte[] verifyToken = SecurityHelper.generateVerifyToken();
        final String sessionId = Long.toString(RANDOM.nextLong(), 16).trim();
        // Store the auth data
        context.getChannel().attr(AUTH_DATA).set(new LoginAuthData(username, sessionId, verifyToken));
        // Send created request message and wait for the response
        session.send(new MessageLoginOutEncryptionRequest(sessionId, publicKey, verifyToken));
    } else {
        // Remove the encryption handler placeholder
        context.getChannel().pipeline().remove(NetworkSession.ENCRYPTION);
        LanternGameProfile profile = context.getChannel().attr(SPOOFED_GAME_PROFILE).getAndSet(null);
        if (profile != null) {
            profile = new LanternGameProfile(profile.getUniqueId(), username, profile.getPropertyMap());
        } else {
            // Try the online id first
            try {
                profile = (LanternGameProfile) Lantern.getGame().getGameProfileManager().get(username).get();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                // Generate a offline id
                final UUID uniqueId = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
                profile = new LanternGameProfile(uniqueId, username);
            }
        }
        session.messageReceived(new MessageLoginInFinish(profile));
    }
}
Also used : NetworkSession(org.lanternpowered.server.network.NetworkSession) MessageLoginOutEncryptionRequest(org.lanternpowered.server.network.vanilla.message.type.login.MessageLoginOutEncryptionRequest) LanternGameProfile(org.lanternpowered.server.profile.LanternGameProfile) ExecutionException(java.util.concurrent.ExecutionException) UUID(java.util.UUID) MessageLoginInFinish(org.lanternpowered.server.network.vanilla.message.type.login.MessageLoginInFinish)

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