package com.ingotpowered.net;
import com.ingotpowered.IngotPlayer;
import com.ingotpowered.IngotServer;
import com.ingotpowered.api.Ingot;
import com.ingotpowered.api.Position;
import com.ingotpowered.api.events.list.PlayerClickEvent;
import com.ingotpowered.api.events.list.PlayerLoginAttemptEvent;
import com.ingotpowered.api.events.list.ServerPingEvent;
import com.ingotpowered.net.codec.AesCodec;
import com.ingotpowered.net.http.HttpHandler;
import com.ingotpowered.net.http.HttpPostRequest;
import com.ingotpowered.net.packets.handshake.Packet0Handshake;
import com.ingotpowered.net.packets.login.Packet0Disconnect;
import com.ingotpowered.net.packets.login.Packet0LoginStart;
import com.ingotpowered.net.packets.login.Packet1Encryption;
import com.ingotpowered.net.packets.ping.Packet0Status;
import com.ingotpowered.net.packets.ping.Packet1Ping;
import com.ingotpowered.net.packets.play.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import javax.crypto.Cipher;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.*;
import java.util.Random;
import java.util.regex.Pattern;
public class PacketHandler {
public static final String SESSIONSERVER_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=${username}&serverId=${hash}";
private static final PublicKey publicKey;
private static final PrivateKey privateKey;
private static Random random = new Random(System.currentTimeMillis());
static {
try {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024);
KeyPair keypair = gen.genKeyPair();
publicKey = keypair.getPublic();
privateKey = keypair.getPrivate();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public IngotPlayer ingotPlayer;
public int waitingPingId = -1;
public long pingSentTimestamp = System.currentTimeMillis() + 10000;
public PacketHandler(IngotPlayer ingotPlayer) {
this.ingotPlayer = ingotPlayer;
}
public void handshake(Packet0Handshake packet) {
ingotPlayer.hostname = packet.hostname;
ingotPlayer.port = packet.port;
if (packet.nextState == 1) {
ingotPlayer.packetCodec.protoState = ProtoState.PING;
} else if (packet.nextState == 2) {
ingotPlayer.packetCodec.protoState = ProtoState.LOGIN;
} else {
ingotPlayer.kick("Invalid packet state!");
}
}
// -- BEGIN Server List Ping --
public void statusRequest(final Packet0Status packet) {
// IngotServer event
final ServerPingEvent event = new ServerPingEvent(Ingot.VERSION_NAME, Ingot.PROTOCOL_VERSION, 0, IngotServer.server.config.getMaxPlayers(), IngotServer.server.config.getMOTD());
IngotServer.server.eventFactory.callEvent(event, new Runnable() {
public void run() {
packet.description = event.getMOTD();
packet.maxPlayers = event.getMaxPlayers();
packet.onlineCount = event.getOnlinePlayersDisplayCount();
packet.protocol = event.getProtocol();
packet.version = event.getVersionName();
ingotPlayer.channel.pipeline().writeAndFlush(packet);
}
});
}
public void ping(Packet1Ping packet) {
ingotPlayer.channel.pipeline().writeAndFlush(packet);
}
// -- BEGIN Login Authentication --
public void loginStart(Packet0LoginStart packet) {
if (ingotPlayer.username != null) {
ingotPlayer.channel.pipeline().writeAndFlush(new Packet0Disconnect("Stop repeating yourself"));
ingotPlayer.channel.close();
return;
}
ingotPlayer.username = packet.name;
// IngotServer Event
final PlayerLoginAttemptEvent event = new PlayerLoginAttemptEvent(ingotPlayer.username, ingotPlayer.hostname, (short) ingotPlayer.port);
IngotServer.server.eventFactory.callEvent(event, new Runnable() {
public void run() {
if (event.isCancelled()) {
ingotPlayer.kick(event.getDisconnectMessage());
return;
}
if (IngotServer.server.config.isOnlineMode()) {
Packet1Encryption response = new Packet1Encryption();
response.publicKey = PacketHandler.publicKey.getEncoded();
byte[] verify = new byte[16];
random.nextBytes(verify);
response.verifyToken = verify;
ingotPlayer.channel.pipeline().writeAndFlush(response);
} else {
ingotPlayer.playerAuthenticated();
}
}
});
}
public void startEncryption(Packet1Encryption packet) {
if (ingotPlayer.username == null) {
ingotPlayer.kick("Identify yourself, stranger!");
return;
}
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, PacketHandler.privateKey);
byte[] iv = cipher.doFinal(packet.publicKey);
ingotPlayer.channel.pipeline().addFirst(new AesCodec(iv));
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.reset();
sha1.update("".getBytes("ISO_8859_1"));
sha1.update(iv);
sha1.update(publicKey.getEncoded());
String hash = URLEncoder.encode(new BigInteger(sha1.digest()).toString(16), "UTF-8");
new HttpPostRequest(SESSIONSERVER_URL.replace("${username}", ingotPlayer.username).replace("${hash}", hash), new HttpHandler() {
public void onError(Channel channel, Throwable cause) {
channel.close();
cause.printStackTrace();
}
public void onSuccess(ChannelHandlerContext context, String data) {
String[] hackSplit = data.split(Pattern.quote("\""));
ingotPlayer.username = hackSplit[7];
ingotPlayer.base64Skin = hackSplit[17];
String uuid = hackSplit[3];
ingotPlayer.uuid = uuid.substring(0, 8) + "-" + uuid.substring(8, 12) + "-" + uuid.substring(12, 16) + "-" + uuid.substring(16, 20) + "-" + uuid.substring(20, 32);
ingotPlayer.playerAuthenticated();
}
});
} catch (Exception ex) {
ingotPlayer.kick("Handshake error: Could not enable encryption!");
ex.printStackTrace();
}
}
// -- BEGIN Player Play message --
public void keepAlive(Packet0KeepAlive packet) {
if (packet.id == waitingPingId) {
ingotPlayer.ping = System.currentTimeMillis() - pingSentTimestamp;
ingotPlayer.packetHandler.waitingPingId = -1;
}
}
public void clientSettings(Packet15ClientSettings packet) {
ingotPlayer.locale = packet.locale;
ingotPlayer.viewDistance = Math.min(packet.viewDistance, IngotServer.server.config.getViewDistance());
ingotPlayer.chatFlags = packet.chatFlags;
ingotPlayer.showingColors = packet.showChatColors;
ingotPlayer.displaySkinParts = packet.displaySkinParts;
}
public void chat(PacketChat packet) {
ingotPlayer.playerChat(packet.message);
}
public void pluginMessage(PacketPluginMessage packet) {
}
public void positionUpdate(Packet4Position packet) {
ingotPlayer.updatePositionAndOrientation(packet.x, packet.feetY, packet.z, ingotPlayer.yaw, ingotPlayer.pitch);
}
public void positionAndOrientationUpdate(PacketPlayerPosLook packet) {
ingotPlayer.updatePositionAndOrientation(packet.x, packet.feetY, packet.z, packet.yaw, packet.pitch);
}
public void heldItemChange(Packet9HeldItem packet) {
}
public void playerLook(Packet5PlayerLook packet) {
ingotPlayer.groundStateChange(packet.onGround);
ingotPlayer.yaw = packet.yaw;
ingotPlayer.pitch = packet.pitch;
}
public void groundStatus(Packet3GroundStatus packet) {
ingotPlayer.groundStateChange(packet.onGround);
}
public void entityAction(Packet11EntityAction packet) {
switch (packet.actionId) {
case 0:
ingotPlayer.crouched = true; break;
case 1:
ingotPlayer.crouched = false; break;
case 2:
/* Leave Bed */ break;
case 3:
ingotPlayer.sprinting = true; break;
case 4:
ingotPlayer.sprinting = false; break;
case 5:
/* Jump w/ horse */ break;
case 6:
/* Open inventory */ break;
default:
ingotPlayer.kick("Unknown EntityAction " + (int) packet.actionId); break;
}
}
public void playerAnimation(Packet10Animation packet) {
final PlayerClickEvent event = new PlayerClickEvent(ingotPlayer, null, (byte) -1);
IngotServer.server.eventFactory.callEvent(event, null);
}
public void digBlockStatus(Packet7DigBlock packet) {
if (packet.status < 0 || packet.status > 5) {
ingotPlayer.kick("Invalid dig packet status!");
ingotPlayer.channel.close();
return;
}
if (packet.status == 0 || packet.status == 1) { // Interact event
final PlayerClickEvent event = new PlayerClickEvent(ingotPlayer, Position.fromLong(packet.position), packet.face);
IngotServer.server.eventFactory.callEvent(event, new Runnable() {
public void run() {
// Call setBlock to reset the block
}
});
} else if (packet.status == 2) { // Block break
} else if (packet.status == 3 || packet.status == 4) { // Drop item stack, item, respectively
} else if (packet.status == 5) { // Shoot arrow or finish eating - check item in hand
}
}
public void blockPlace(Packet8BlockPlace packet) {
}
public void playerUseEntity(Packet2UseEntity packet) {
}
}