From 22fe9568bdb177648f59962814712944d1398708 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 18 Nov 2022 00:20:42 +0100 Subject: [PATCH] Split base64 over several items to insert newlines --- src/dec/mod.rs | 30 ++++++++++++++++++++++++------ src/enc/mod.rs | 16 +++++++++++----- src/lib.rs | 13 +++++++++---- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/dec/mod.rs b/src/dec/mod.rs index 653e5f7..5c50550 100644 --- a/src/dec/mod.rs +++ b/src/dec/mod.rs @@ -385,13 +385,31 @@ impl<'a, 'b> Term<'a, 'b> { /// assert_eq!(term.bytes().unwrap(), b"hello, world!"); /// ``` pub fn bytes(&self) -> Result, TypeError> { - let encoded = match &self.0 { - AnyTerm::Str(s) => s, - AnyTerm::List(r, l) if l.iter().all(|x| matches!(x, NonListTerm::Str(_))) => r, - _ => return Err(TypeError::WrongType("BYTES")), + let decode = |encoded| { + base64::decode_config(encoded, base64::URL_SAFE_NO_PAD) + .map_err(|_| TypeError::WrongType("BYTES")) }; - base64::decode_config(encoded, base64::URL_SAFE_NO_PAD) - .map_err(|_| TypeError::WrongType("BYTES")) + match self.0.mkref() { + AnyTerm::Str(encoded) => { + if encoded == b"." { + Ok(vec![]) + } else { + decode(encoded) + } + } + AnyTerm::ListRef(_, list) => { + let mut ret = Vec::with_capacity(128); + for term in list.iter() { + if let NonListTerm::Str(encoded) = term { + ret.extend(decode(encoded)?) + } else { + return Err(TypeError::WrongType("BYTES")); + } + } + Ok(ret) + } + _ => Err(TypeError::WrongType("BYTES")), + } } /// Try to interpret this string as base64-encoded bytes, diff --git a/src/enc/mod.rs b/src/enc/mod.rs index ef8e563..03029f8 100644 --- a/src/enc/mod.rs +++ b/src/enc/mod.rs @@ -123,10 +123,16 @@ pub fn dict<'a, I: IntoIterator)>>(pairs: I) -> Term<' /// /// assert_eq!(encode(bytes(b"hello, world!")).unwrap(), b"aGVsbG8sIHdvcmxkIQ"); /// ``` -pub fn bytes(b: &[u8]) -> Term<'static> { - Term(T::OwnedStr( - base64::encode_config(b, base64::URL_SAFE_NO_PAD).into_bytes(), - )) +pub fn bytes(bytes: &[u8]) -> Term<'static> { + let chunks = bytes + .chunks(48) + .map(|b| T::OwnedStr(base64::encode_config(b, base64::URL_SAFE_NO_PAD).into_bytes())) + .collect::>(); + if chunks.len() > 1 { + Term(T::List(chunks)) + } else { + Term(chunks.into_iter().next().unwrap_or(T::Str(b"."))) + } } impl<'a> Term<'a> { @@ -197,7 +203,7 @@ fn encode_aux(buf: &mut Vec, term: T<'_>, indent: usize) -> Result<(), Error T::List(l) => { let indent2 = indent + 2; for (i, v) in l.into_iter().enumerate() { - if buf.iter().rev().take_while(|c| **c != b'\n').count() > 80 { + if buf.iter().rev().take_while(|c| **c != b'\n').count() >= 70 { buf.push(b'\n'); for _ in 0..indent2 { buf.push(b' '); diff --git a/src/lib.rs b/src/lib.rs index 95c375c..4555f14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,21 +55,26 @@ //! a = hello, //! b = world, //! c = { a = 12, b = 42 }, -//! } gTjRjHtSX6OCwq3pdl9Bpg6M2h-2WkciKi0uNV8NQX0 +//! } YutjCfgXXYNkNR1IQiNi3pFKpvqfwICkLc3EJOekcq4 //! ``` //! //! And the value of `text2` would be as follows: //! ```raw //! { -//! hash = BEBZp98KF_d1rvBd5Ib8q1w_oGvrvIcKRXFv9kMB0ewOWH42OPd8qa0V_2ranV92z0mEdswftqvpAYebziTIew, +//! hash = IT4ay3XM4SycgYjxV8_Ioxqqt9JwdFK0sZqd-TOhOl9IGxbTQwK8vPy409h59xCV +//! NrMjDC1YIS7bXIrrv_Tvbw, //! payload = CALL myfunction { //! a = hello, //! b = world, //! c = { a = 12, b = 42 }, -//! } gTjRjHtSX6OCwq3pdl9Bpg6M2h-2WkciKi0uNV8NQX0, -//! signature = rAwIUTsCdoB_4eqo7r5e_J5ZHFaxHnXi99oNWi7h7y0mRfgt5u7-qXn7spIN1GcmDWYh4EPzoY34Br-sRxi0AA, +//! } YutjCfgXXYNkNR1IQiNi3pFKpvqfwICkLc3EJOekcq4, +//! signature = UFje_N6vnrN23-ygB1yr8LwSipSwxrMLEB2ov6bvU4rR9BmfLjxyq8zTzKxb_VNw +//! UABMRcy-KiITwpY_b3UdBg, //! } //! ``` +//! +//! Note that the value of `text1` is embedded as-is inside `text2`. This is what allows us +//! to check the hash and the signature: the raw representation of the term hasn't changed. pub mod crypto; pub mod dec;