package net.scapeemulator.game.net.login;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.io.IOException;
import net.scapeemulator.util.Base37Utils;
import net.scapeemulator.util.ByteBufUtils;
import net.scapeemulator.util.crypto.RsaKeySet;
public final class LoginDecoder extends ByteToMessageDecoder {
private enum State {
READ_HEADER, READ_PAYLOAD
}
private int hash, type, size;
private State state = State.READ_HEADER;
@Override
public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) throws IOException {
if (state == State.READ_HEADER) {
if (buf.readableBytes() < 4)
return;
state = State.READ_PAYLOAD;
hash = buf.readUnsignedByte();
type = buf.readUnsignedByte();
size = buf.readUnsignedShort();
if (type != 16 && type != 18)
throw new IOException("Invalid login type.");
}
if (state == State.READ_PAYLOAD) {
if (buf.readableBytes() < size)
return;
int version = buf.readInt();
buf.readUnsignedByte();
buf.readUnsignedByte();
buf.readUnsignedByte();
int displayMode = buf.readUnsignedByte(); // 0 = sd, 1 = hd small, 2 = hd resizable
int width = buf.readUnsignedShort();
int height = buf.readUnsignedShort();
int antialiasing = buf.readUnsignedByte();
byte[] uid = new byte[24];
for (int i = 0; i < uid.length; i++)
uid[i] = buf.readByte();
String settings = ByteBufUtils.readString(buf);
int affiliate = buf.readInt();
int flags = buf.readInt();
buf.readShort();
int[] crc = new int[28];
for (int i = 0; i < crc.length; i++)
crc[i] = buf.readInt();
int encryptedSize = buf.readUnsignedByte();
ByteBuf secureBuffer = ByteBufUtils.rsa(buf.readBytes(encryptedSize), RsaKeySet.MODULUS, RsaKeySet.PRIVATE_KEY);
int encryptedType = secureBuffer.readUnsignedByte();
if (encryptedType != 10)
throw new IOException("Invalid encrypted block type.");
long clientSessionKey = secureBuffer.readLong();
long serverSessionKey = secureBuffer.readLong();
long encodedUsername = secureBuffer.readLong();
String username = Base37Utils.decodeBase37(encodedUsername);
String password = ByteBufUtils.readString(secureBuffer);
if (((encodedUsername >> 16) & 31) != hash)
throw new IOException("Username hash mismatch.");
boolean reconnecting = type == 16;
out.add(new LoginRequest(reconnecting, username, password, clientSessionKey, serverSessionKey, version, crc, displayMode));
ctx.pipeline().remove(this);
}
}
}