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;
}
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)));
}
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));
}
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());
});
}
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));
}
}
Aggregations