From e120cd547d4bbde96d6513edda0a74ba394588c1 Mon Sep 17 00:00:00 2001 From: Avril Date: Wed, 18 Nov 2020 17:25:25 +0000 Subject: [PATCH] mod b64 oke --- src/conv.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/conv.rs b/src/conv.rs index 9ee8bf3..febf156 100644 --- a/src/conv.rs +++ b/src/conv.rs @@ -5,27 +5,43 @@ use std::{ borrow::Borrow, fmt, error, + convert::TryFrom, }; use regex::{ Regex, }; const BASE64_VALIDATE_RE_STR: &'static str = r#"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"#; +const MOD_BASE64_VALIDATE_RE_STR: &'static str = r#"^(?:[-A-Za-z0-9_]{4})*(?:[-_A-Za-z0-9]{2}==|[-_A-Za-z0-9]{3}=)?$"#; lazy_static!{ static ref BASE64_CONV_TABLE: smallmap::Map = smallmap![ {'/' => '_'}, - {'+' => 'ł'}, - {'=' => '-'}, + {'+' => '-'}, ]; static ref BASE64_CONV_TABLE_REV: smallmap::Map = BASE64_CONV_TABLE.clone().reverse(); static ref BASE64_VALIDATE_REGEX: Regex = Regex::new(BASE64_VALIDATE_RE_STR).expect("Failed to compile base64 validation regex"); + static ref MOD_BASE64_VALIDATE_REGEX: Regex = Regex::new(MOD_BASE64_VALIDATE_RE_STR).expect("Failed to compile modified base64 validation regex"); } #[derive(Debug)] pub struct Base64Error(T); +impl Base64Error +{ + /// The invalid value of this error + pub fn value(&self) -> &T + { + &self.0 + } + /// Consume into the invalid value from this instance + #[inline] pub fn into_inner(self) -> T + { + self.0 + } +} + impl error::Error for Base64Error where T: AsRef + fmt::Debug{} impl fmt::Display for Base64Error @@ -52,7 +68,7 @@ impl fmt::Display for ModifiedBase64String impl ModifiedBase64String { - fn from_base64_unchecked(string: &str) -> Self + #[inline(always)] fn from_base64_unchecked(string: &str) -> Self { Self(conv_str(&BASE64_CONV_TABLE, string).collect()) } @@ -63,6 +79,22 @@ impl ModifiedBase64String conv_char_iter(&BASE64_CONV_TABLE_REV, self.0.chars()).collect() } + /// Consume into the inner modified base64 string + pub fn into_string(self) -> String + { + self.0 + } + + /// Create an instance from a modified base64 string + pub fn new(from: String) -> Result> + { + if MOD_BASE64_VALIDATE_REGEX.is_match(from.as_str()) { + Ok(Self(from)) + } else { + Err(Base64Error(from)) + } + } + /// Try to convert a base64 string into a modified base64 string pub fn try_from_base64>(base64: T) -> Result> { @@ -115,6 +147,24 @@ impl AsRef for ModifiedBase64String } } +impl TryFrom for ModifiedBase64String +{ + type Error = Base64Error; + + #[inline] fn try_from(from: String) -> Result + { + Self::try_from_base64(from) + } +} + +impl From for String +{ + #[inline] fn from(from: ModifiedBase64String) -> Self + { + from.into_base64() + } +} + /// Convert this string with a specified char map. Returns a `char` yielding iterator. #[inline] pub fn conv_str<'a, 'b>(table: &'b smallmap::Map, string: &'a (impl AsRef + ?Sized)) -> CharSubstituteIter<'b, std::str::Chars<'a>> @@ -131,3 +181,19 @@ where I: IntoIterator, { iter.replace_chars(table) } + +#[cfg(test)] +mod tests +{ + #[test] + fn mod_base64_enc_dec() + { + let mut value = [0u8; 512]; + getrandom::getrandom(&mut value[..]).expect("setup failed"); + + let md = super::ModifiedBase64String::encode(&value[..]); + println!("e-md: {:?}", md); + let ou = md.decode_new(); + assert_eq!(&ou[..], &value[..]); + } +}