package com.eu.habbo.networking.gameserver.crypto;

import com.eu.habbo.networking.gameserver.GameServerAttributes;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class WsAesDecoder extends MessageToMessageDecoder<ByteBuf> {
    private static final Logger LOGGER = LoggerFactory.getLogger(WsAesDecoder.class);

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        byte[] key = ctx.channel().attr(GameServerAttributes.WS_AES_KEY).get();
        if (key == null) {
            LOGGER.warn("[ws-crypto] inbound frame with no session key, closing");
            ctx.close();
            return;
        }

        int readable = in.readableBytes();
        if (readable < WsSessionCrypto.NONCE_LEN + 16) {
            LOGGER.warn("[ws-crypto] inbound frame too short ({} bytes)", readable);
            ctx.close();
            return;
        }

        byte[] nonce = new byte[WsSessionCrypto.NONCE_LEN];
        in.readBytes(nonce);

        byte[] ct = new byte[in.readableBytes()];
        in.readBytes(ct);

        try {
            byte[] plain = WsSessionCrypto.aesGcmDecrypt(key, nonce, ct);
            out.add(Unpooled.wrappedBuffer(plain));
        } catch (Exception e) {
            LOGGER.warn("[ws-crypto] AES-GCM decrypt failed ({}), closing channel", e.getClass().getSimpleName());
            ctx.close();
        }
    }
}
