<commit_before>package io.luna.net.codec.login;

import com.moandjiezana.toml.Toml;
import io.luna.LunaContext;
import io.luna.net.client.Client;
import io.luna.net.client.LoginClient;
import io.luna.net.codec.ByteMessage;
import io.luna.net.codec.IsaacCipher;
import io.luna.net.codec.ProgressiveMessageDecoder;
import io.luna.net.msg.GameMessageRepository;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.Attribute;

import java.io.File;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;

import static com.google.common.base.Preconditions.checkState;

/**
 * A {@link ByteToMessageDecoder} implementation that decodes a {@link LoginRequestMessage}.
 *
 * @author lare96 <http://github.org/lare96>
 */
public final class LoginDecoder extends ProgressiveMessageDecoder<LoginDecoder.DecodeState> {

    static {
        try {
            // Initializes RSA modulus and exponent values.
            Toml tomlReader = new Toml().
                    read(new File("./data/rsa/rsapriv.toml")).
                    getTable("key");
            RSA_MOD = new BigInteger(tomlReader.getString("modulus"));
            RSA_EXP = new BigInteger(tomlReader.getString("exponent"));
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * An enumerated type representing login decoder states.
     */
    enum DecodeState {
        HANDSHAKE,
        LOGIN_TYPE,
        RSA_BLOCK
    }

    /**
     * The private RSA modulus value.
     */
    private static final BigInteger RSA_MOD;

    /**
     * The private RSA exponent value.
     */
    private static final BigInteger RSA_EXP;

    /**
     * A cryptographically secure RNG.
     */
    private static final Random RANDOM = new SecureRandom();

    /**
     * The size of the RSA block.
     */
    private int rsaBlockSize;

    /**
     * The context instance.
     */
    private final LunaContext context;

    /**
     * The message repository.
     */
    private final GameMessageRepository repository;

    /**
     * Creates a new {@link LoginDecoder}.
     *
     * @param context The context instance.
     * @param repository The message repository.
     */
    public LoginDecoder(LunaContext context, GameMessageRepository repository) {
        super(DecodeState.HANDSHAKE);
        this.context = context;
        this.repository = repository;
    }

    @Override
    protected Object decodeMsg(ChannelHandlerContext ctx, ByteBuf in, DecodeState state) {
        switch (state) {
            case HANDSHAKE:
                Attribute<Client<?>> attribute = ctx.channel().attr(Client.KEY);
                attribute.set(new LoginClient(ctx.channel(), context, repository));

                decodeHandshake(ctx, in);
                break;
            case LOGIN_TYPE:
                decodeLoginType(ctx, in);
                break;
            case RSA_BLOCK:
                return decodeRsaBlock(ctx, in);

        }
        return null;
    }

    @Override
    protected void resetState() {
        rsaBlockSize = 0;
    }

    /**
     * Decodes the handshake.
     *
     * @param ctx The channel handler context.
     * @param in The buffer to read data from.
     */
    private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf in) {
        if (in.readableBytes() >= 2) {
            int opcode = in.readUnsignedByte(); // TODO Ondemand?

            @SuppressWarnings("unused") int nameHash = in.readUnsignedByte();

            // TODO WHEN AN EXCEPTION IS THROWN HERE THE PLAYER GETS STUCK LOGGED IN?<commit_msg>Error handling for the login decoder<commit_after>package io.luna.net.codec.login;

import com.moandjiezana.toml.Toml;
import io.luna.LunaContext;
import io.luna.net.client.Client;
import io.luna.net.client.LoginClient;
import io.luna.net.codec.ByteMessage;
import io.luna.net.codec.IsaacCipher;
import io.luna.net.codec.ProgressiveMessageDecoder;
import io.luna.net.msg.GameMessageRepository;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.Attribute;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;

import static com.google.common.base.Preconditions.checkState;

/**
 * A {@link ByteToMessageDecoder} implementation that decodes a {@link LoginRequestMessage}.
 *
 * @author lare96 <http://github.org/lare96>
 */
public final class LoginDecoder extends ProgressiveMessageDecoder<LoginDecoder.DecodeState> {

    static {
        try {
            // Initializes RSA modulus and exponent values.
            Toml tomlReader = new Toml().
                    read(new File("./data/rsa/rsapriv.toml")).
                    getTable("key");
            RSA_MOD = new BigInteger(tomlReader.getString("modulus"));
            RSA_EXP = new BigInteger(tomlReader.getString("exponent"));
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * An enumerated type representing login decoder states.
     */
    enum DecodeState {
        HANDSHAKE,
        LOGIN_TYPE,
        RSA_BLOCK
    }

    /**
     * The asynchronous logger.
     */
    private static final Logger logger = LogManager.getLogger();

    /**
     * The private RSA modulus value.
     */
    private static final BigInteger RSA_MOD;

    /**
     * The private RSA exponent value.
     */
    private static final BigInteger RSA_EXP;

    /**
     * A cryptographically secure RNG.
     */
    private static final Random RANDOM = new SecureRandom();

    /**
     * The size of the RSA block.
     */
    private int rsaBlockSize;

    /**
     * The context instance.
     */
    private final LunaContext context;

    /**
     * The message repository.
     */
    private final GameMessageRepository repository;

    /**
     * Creates a new {@link LoginDecoder}.
     *
     * @param context The context instance.
     * @param repository The message repository.
     */
    public LoginDecoder(LunaContext context, GameMessageRepository repository) {
        super(DecodeState.HANDSHAKE);
        this.context = context;
        this.repository = repository;
    }

    @Override
    protected Object decodeMsg(ChannelHandlerContext ctx, ByteBuf in, DecodeState state) {
        switch (state) {
            case HANDSHAKE:
                Attribute<Client<?>> attribute = ctx.channel().attr(Client.KEY);
                attribute.set(new LoginClient(ctx.channel(), context, repository));

                decodeHandshake(ctx, in);
                break;
            case LOGIN_TYPE:
                decodeLoginType(ctx, in);
                break;
            case RSA_BLOCK:
                return decodeRsaBlock(ctx, in);

        }
        return null;
    }

    @Override
    protected void resetState() {
        rsaBlockSize = 0;
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("An error was thrown by the login decoder!", cause);
        ctx.channel().close();
    }

    /**
     * Decodes the handshake.
     *
     * @param ctx The channel handler context.
     * @param in The buffer to read data from.
     */
    private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf in) {
        if (in.readableBytes() >= 2) {
            int opcode = in.readUnsignedByte(); // TODO Ondemand?

            @SuppressWarnings("unused") int nameHash = in.readUnsignedByte();

            // TODO WHEN AN EXCEPTION IS THROWN HERE THE PLAYER GETS STUCK LOGGED IN?
{'fraction_non_alphanumeric': 0.09774436090225563, 'fraction_numerical': 0.001784121320249777, 'mean_word_length': 2.374032674118659, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1213790', 'n_tokens_mistral': 2268, 'n_tokens_neox': 2152, 'n_words': 560}