use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
pub fn base64_url_encode<T: AsRef<[u8]>>(payload: T) -> String {
URL_SAFE_NO_PAD.encode(payload)
}
pub fn base64_url_decode<T: AsRef<[u8]>>(payload: T) -> Result<Vec<u8>, base64::DecodeError> {
URL_SAFE_NO_PAD.decode(payload)
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use super::*;
const TEST_CASES: [(&str, &str); 4] = [
("Hello, World!", "SGVsbG8sIFdvcmxkIQ"),
("", ""),
("Rust! 🚀", "UnVzdCEg8J-agA"),
("no padding here", "bm8gcGFkZGluZyBoZXJl"),
];
#[test]
fn test_base64_url_encode() {
for (input, expected) in TEST_CASES {
let result = base64_url_encode(input);
assert_eq!(result, expected, "{input}");
}
}
#[test]
fn test_base64_url_encode_binary_data() {
let input = [0xDE, 0xAD, 0xBE, 0xEF];
let expected = "3q2-7w";
let result = base64_url_encode(input);
assert_eq!(result, expected);
}
#[test]
fn test_base64_url_decode() {
for (expected, input) in TEST_CASES {
let result = base64_url_decode(input).unwrap();
assert_eq!(result, expected.as_bytes(), "{input}");
}
}
#[test]
fn test_base64_url_decode_binary_data() {
let input = "3q2-7w";
let expected = [0xDE, 0xAD, 0xBE, 0xEF];
let result = base64_url_decode(input).unwrap();
assert_eq!(result, expected);
}
#[test]
fn test_base64_url_decode_padded_input() {
let input = "SGVsbG8sIFdvcmxkIQ==";
let err = base64_url_decode(input).unwrap_err();
assert_matches!(err, base64::DecodeError::InvalidPadding);
}
#[test]
fn test_base64_url_decode_invalid_input() {
let input = "inv@lid";
let err = base64_url_decode(input).unwrap_err();
assert_matches!(err, base64::DecodeError::InvalidByte(3, b'@'));
}
}