use std::{
convert::TryFrom,
io::{Cursor, Write},
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bytes::Bytes;
use crate::{bytes_ext::BytesReaderExt, Error};
const REJECTED_RPC_MISMATCH: u32 = 0;
const REJECTED_AUTH_ERROR: u32 = 1;
const AUTH_ERROR_SUCCESS: u32 = 0;
const AUTH_ERROR_BADCRED: u32 = 1;
const AUTH_ERROR_REJECTEDCRED: u32 = 2;
const AUTH_ERROR_BADVERF: u32 = 3;
const AUTH_ERROR_REJECTEDVERF: u32 = 4;
const AUTH_ERROR_TOOWEAK: u32 = 5;
const AUTH_ERROR_INVALIDRESP: u32 = 6;
const AUTH_ERROR_FAILED: u32 = 7;
#[derive(Debug, PartialEq)]
pub enum RejectedReply {
RpcVersionMismatch {
low: u32,
high: u32,
},
AuthError(AuthError),
}
impl RejectedReply {
pub(crate) fn from_cursor(r: &mut Cursor<&[u8]>) -> Result<Self, Error> {
let reply = match r.read_u32::<BigEndian>()? {
REJECTED_RPC_MISMATCH => Self::RpcVersionMismatch {
low: r.read_u32::<BigEndian>()?,
high: r.read_u32::<BigEndian>()?,
},
REJECTED_AUTH_ERROR => Self::AuthError(AuthError::from_cursor(r)?),
v => return Err(Error::InvalidRejectedReplyType(v)),
};
Ok(reply)
}
pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
match self {
Self::RpcVersionMismatch { low: l, high: h } => {
buf.write_u32::<BigEndian>(REJECTED_RPC_MISMATCH)?;
buf.write_u32::<BigEndian>(*l)?;
buf.write_u32::<BigEndian>(*h)
}
Self::AuthError(err) => {
buf.write_u32::<BigEndian>(REJECTED_AUTH_ERROR)?;
err.serialise_into(buf)
}
}
}
pub fn serialised_len(&self) -> u32 {
let mut len = 0;
len += 4;
len += match self {
Self::RpcVersionMismatch {
low: _low,
high: _high,
} => {
4 + 4
}
Self::AuthError(e) => e.serialised_len(),
};
len
}
}
impl TryFrom<&[u8]> for RejectedReply {
type Error = Error;
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
let mut c = Cursor::new(v);
Self::from_cursor(&mut c)
}
}
impl TryFrom<Bytes> for RejectedReply {
type Error = Error;
fn try_from(mut v: Bytes) -> Result<Self, Self::Error> {
let reply = match v.try_u32()? {
REJECTED_RPC_MISMATCH => Self::RpcVersionMismatch {
low: v.try_u32()?,
high: v.try_u32()?,
},
REJECTED_AUTH_ERROR => Self::AuthError(AuthError::try_from(v)?),
v => return Err(Error::InvalidRejectedReplyType(v)),
};
Ok(reply)
}
}
#[derive(Debug, PartialEq)]
pub enum AuthError {
Success,
BadCredentials,
RejectedCredentials,
BadVerifier,
RejectedVerifier,
TooWeak,
InvalidResponseVerifier,
Failed,
}
impl AuthError {
pub(crate) fn from_cursor(r: &mut Cursor<&[u8]>) -> Result<Self, Error> {
let reply = match r.read_u32::<BigEndian>()? {
AUTH_ERROR_SUCCESS => Self::Success,
AUTH_ERROR_BADCRED => Self::BadCredentials,
AUTH_ERROR_REJECTEDCRED => Self::RejectedCredentials,
AUTH_ERROR_BADVERF => Self::BadVerifier,
AUTH_ERROR_REJECTEDVERF => Self::RejectedVerifier,
AUTH_ERROR_TOOWEAK => Self::TooWeak,
AUTH_ERROR_INVALIDRESP => Self::InvalidResponseVerifier,
AUTH_ERROR_FAILED => Self::Failed,
v => return Err(Error::InvalidAuthError(v)),
};
Ok(reply)
}
pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
let id = match self {
Self::Success => AUTH_ERROR_SUCCESS,
Self::BadCredentials => AUTH_ERROR_BADCRED,
Self::RejectedCredentials => AUTH_ERROR_REJECTEDCRED,
Self::BadVerifier => AUTH_ERROR_BADVERF,
Self::RejectedVerifier => AUTH_ERROR_REJECTEDVERF,
Self::TooWeak => AUTH_ERROR_TOOWEAK,
Self::InvalidResponseVerifier => AUTH_ERROR_INVALIDRESP,
Self::Failed => AUTH_ERROR_FAILED,
};
buf.write_u32::<BigEndian>(id)
}
pub fn serialised_len(&self) -> u32 {
4
}
}
impl TryFrom<Bytes> for AuthError {
type Error = Error;
fn try_from(mut v: Bytes) -> Result<Self, Self::Error> {
let reply = match v.try_u32()? {
AUTH_ERROR_SUCCESS => Self::Success,
AUTH_ERROR_BADCRED => Self::BadCredentials,
AUTH_ERROR_REJECTEDCRED => Self::RejectedCredentials,
AUTH_ERROR_BADVERF => Self::BadVerifier,
AUTH_ERROR_REJECTEDVERF => Self::RejectedVerifier,
AUTH_ERROR_TOOWEAK => Self::TooWeak,
AUTH_ERROR_INVALIDRESP => Self::InvalidResponseVerifier,
AUTH_ERROR_FAILED => Self::Failed,
v => return Err(Error::InvalidAuthError(v)),
};
Ok(reply)
}
}