tentacli 15.2.3

Framework for building extensible network protocol clients via modular plugins.
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
use std::io::{Cursor, Read};

use crate::client::prelude::*;
use crate::plugins::wow::wotlk::login::Secret;
use crate::plugins::wow::wotlk::opcodes::Opcode;
use crate::plugins::wow::wotlk::realm::rc4::{Decryptor, Encryptor};

const OPCODE_SIZE: usize = 2;

#[derive(Default)]
pub struct PacketReader {
    decryptor: Option<Decryptor>,
    is_decrypted: bool,
}

impl BytesRead for PacketReader {
    fn read(&mut self, buffer: &mut [u8], context: &CtxMap) -> anyhow::Result<Packet> {
        if buffer.len() < 4 {
            anyhow::bail!("Incomplete header... continue reading.");
        }

        let mut header = buffer[..4].to_vec();
        let mut is_long_packet = false;

        if !self.is_decrypted
            && let Some(decryptor) = self.decryptor.as_mut()
        {
            decryptor.decrypt(&mut header[..1]);

            is_long_packet = (header[0] & 0x80) != 0;

            if is_long_packet {
                if buffer.len() < 5 {
                    anyhow::bail!("Incomplete header (long)... continue reading.");
                }

                let extra_byte = buffer[4];
                header.push(extra_byte);
            }

            decryptor.decrypt(&mut header[1..]);

            buffer[..header.len()].copy_from_slice(&header);
            self.is_decrypted = true;
        }

        let mut header_reader = Cursor::new(&header);

        let size = if is_long_packet {
            header_reader.read_u24::<BigEndian>()? as usize
        } else {
            header_reader.read_u16::<BigEndian>()? as usize
        };

        let opcode = ReadBytesExt::read_u16::<LittleEndian>(&mut header_reader)?;
        let size = size - OPCODE_SIZE;

        let mut reader = Cursor::new(&mut buffer[header.len()..]);
        let mut body = vec![0u8; size];
        reader.read_exact(&mut body)?;

        if self.decryptor.is_none()
            && let Some(secret) = context.get::<Secret>()
        {
            self.decryptor = Some(Decryptor::new(&secret.0.to_vec()));
        }

        self.is_decrypted = false;

        let mut packet = Packet::default();
        packet.set_type(PacketType::Incoming);
        packet.set_opcode(PacketOpcode::U16(opcode));
        packet.set_packet_name(Opcode::get_opcode_name(opcode as u32).unwrap_or_default());
        packet.set_packet_size(body.len() + header.len());
        packet.set_body(body);

        Ok(packet)
    }
}

#[derive(Default)]
pub struct PacketSerializer {
    encryptor: Option<Encryptor>,
}

impl Serializer for PacketSerializer {
    fn serialize(&mut self, packet: &Packet, context: &CtxMap) -> anyhow::Result<Vec<u8>> {
        let opcode = match packet.metadata.opcode {
            PacketOpcode::U32(opcode) => opcode,
            _ => anyhow::bail!("Wrong opcode type !"),
        };

        let size = (4 + packet.content.body.len()) as u16;

        let mut buffer = Vec::with_capacity(2 + size as usize);
        buffer.extend_from_slice(&size.to_be_bytes());
        buffer.extend_from_slice(&opcode.to_le_bytes());

        if let Some(encryptor) = self.encryptor.as_mut() {
            encryptor.encrypt(&mut buffer);
        }

        buffer.extend_from_slice(&packet.content.body);

        if self.encryptor.is_none()
            && let Some(secret) = context.get::<Secret>()
        {
            self.encryptor = Some(Encryptor::new(&secret.0.to_vec()));
        }

        Ok(buffer)
    }
}