use super::Result;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::io::Cursor;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AlertLevel {
Warning = 1,
Fatal = 2,
Invalid = 255,
}
impl From<u8> for AlertLevel {
fn from(value: u8) -> Self {
match value {
1 => AlertLevel::Warning,
2 => AlertLevel::Fatal,
_ => AlertLevel::Invalid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AlertDescription {
CloseNotify = 0,
UnexpectedMessage = 10,
BadRecordMac = 20,
DecryptionFailed = 21,
RecordOverflow = 22,
DecompressionFailure = 30,
HandshakeFailure = 40,
NoCertificate = 41,
BadCertificate = 42,
UnsupportedCertificate = 43,
CertificateRevoked = 44,
CertificateExpired = 45,
CertificateUnknown = 46,
IllegalParameter = 47,
UnknownCa = 48,
AccessDenied = 49,
DecodeError = 50,
DecryptError = 51,
ExportRestriction = 60,
ProtocolVersion = 70,
InsufficientSecurity = 71,
InternalError = 80,
UserCanceled = 90,
NoRenegotiation = 100,
UnsupportedExtension = 110,
Invalid = 255,
}
impl From<u8> for AlertDescription {
fn from(value: u8) -> Self {
match value {
0 => AlertDescription::CloseNotify,
10 => AlertDescription::UnexpectedMessage,
20 => AlertDescription::BadRecordMac,
21 => AlertDescription::DecryptionFailed,
22 => AlertDescription::RecordOverflow,
30 => AlertDescription::DecompressionFailure,
40 => AlertDescription::HandshakeFailure,
41 => AlertDescription::NoCertificate,
42 => AlertDescription::BadCertificate,
43 => AlertDescription::UnsupportedCertificate,
44 => AlertDescription::CertificateRevoked,
45 => AlertDescription::CertificateExpired,
46 => AlertDescription::CertificateUnknown,
47 => AlertDescription::IllegalParameter,
48 => AlertDescription::UnknownCa,
49 => AlertDescription::AccessDenied,
50 => AlertDescription::DecodeError,
51 => AlertDescription::DecryptError,
60 => AlertDescription::ExportRestriction,
70 => AlertDescription::ProtocolVersion,
71 => AlertDescription::InsufficientSecurity,
80 => AlertDescription::InternalError,
90 => AlertDescription::UserCanceled,
100 => AlertDescription::NoRenegotiation,
110 => AlertDescription::UnsupportedExtension,
_ => AlertDescription::Invalid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Alert {
pub level: AlertLevel,
pub description: AlertDescription,
}
impl Alert {
pub fn new(level: AlertLevel, description: AlertDescription) -> Self {
Self { level, description }
}
pub fn close_notify() -> Self {
Self {
level: AlertLevel::Warning,
description: AlertDescription::CloseNotify,
}
}
pub fn is_fatal(&self) -> bool {
self.level == AlertLevel::Fatal
}
pub fn serialize(&self) -> Result<Bytes> {
let mut buf = BytesMut::with_capacity(2);
buf.put_u8(self.level as u8);
buf.put_u8(self.description as u8);
Ok(buf.freeze())
}
pub fn parse(data: &[u8]) -> Result<Self> {
if data.len() < 2 {
return Err(crate::error::Error::PacketTooShort);
}
let mut cursor = Cursor::new(data);
let level = AlertLevel::from(cursor.get_u8());
let description = AlertDescription::from(cursor.get_u8());
Ok(Self { level, description })
}
}