use super::funejson::Value; use super::encoding_base64_base64_decode::base64_decode; /// base64url text back to bytes. Padding is optional, since JWTs leave it /// off and some producers keep it, but padding that is present must be right. /// /// # Panics /// Panics on a character outside the URL-safe alphabet, an impossible /// length, wrong padding, or non-zero bits after the last byte. pub fn base64_url_decode(text: &str) -> Vec { let mut body = String::with_capacity(text.len() + 2); let mut padding = 0usize; for &b in text.as_bytes() { if b == b'=' { padding += 1; continue; } let ok = b.is_ascii_alphanumeric() || b == b'-' || b == b'_'; if !ok || padding > 0 { panic!("base64url text may only contain A-Z, a-z, 0-9, - and _, with optional = padding at the end"); } body.push(match b { b'-' => '+', b'_' => '/', other => other as char, }); } if body.len() % 4 == 1 { panic!( "base64url text cannot be {} characters long; no number of bytes encodes to that", body.len() ); } let needed = (4 - body.len() % 4) % 4; if padding != 0 && padding != needed { panic!("base64url text has the wrong amount of = padding"); } for _ in 0..needed { body.push('='); } base64_decode(&body) } pub fn fune_vector(args: &[Value]) -> Value { let text = match &args[0] { Value::Str(s) => s.as_str(), _ => panic!("base64url text must be a string"), }; Value::Arr(base64_url_decode(text).into_iter().map(Value::Int).collect()) }