pub mod expected; pub mod not_authorized; pub mod not_valid; pub use expected::Expected; pub use not_authorized::NotAuthorized; pub use not_valid::NotValid; use anyhow::{bail, Result}; /// [Client certificates](https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates) pub enum Certificate { Expected(Expected), NotAuthorized(NotAuthorized), NotValid(NotValid), } impl Certificate { pub fn from_bytes(buffer: &[u8]) -> Result { if buffer.first().is_none_or(|b| *b != b'6') { bail!("Unexpected first byte") } match buffer.get(1) { Some(byte) => Ok(match byte { b'0' => Self::Expected(Expected::from_bytes(buffer)?), b'1' => Self::NotAuthorized(NotAuthorized::from_bytes(buffer)?), b'2' => Self::NotValid(NotValid::from_bytes(buffer)?), b => bail!("Unexpected second byte: {b}"), }), None => bail!("Invalid request"), } } pub fn into_bytes(self) -> Vec { match self { Self::Expected(this) => this.into_bytes(), Self::NotAuthorized(this) => this.into_bytes(), Self::NotValid(this) => this.into_bytes(), } } } #[test] fn test() { // 60 let request = "60 message\r\n"; let source = Certificate::from_bytes(request.as_bytes()).unwrap(); match source { Certificate::Expected(ref this) => assert_eq!(this.message, Some("message".to_string())), _ => panic!(), } assert_eq!(source.into_bytes(), request.as_bytes()); // 61 let request = "61 message\r\n"; let source = Certificate::from_bytes(request.as_bytes()).unwrap(); match source { Certificate::NotAuthorized(ref this) => { assert_eq!(this.message, Some("message".to_string())) } _ => panic!(), } assert_eq!(source.into_bytes(), request.as_bytes()); // 62 let request = "62 message\r\n"; let source = Certificate::from_bytes(request.as_bytes()).unwrap(); match source { Certificate::NotValid(ref this) => assert_eq!(this.message, Some("message".to_string())), _ => panic!(), } assert_eq!(source.into_bytes(), request.as_bytes()); }