use super::{Base64Encodable, PasetoError, UntrustedToken};
use std::fmt;
use std::ops::Deref;
#[derive(Default, Debug, Clone, Copy)]
pub struct Footer<'a>(&'a str);
impl Base64Encodable<str> for Footer<'_> {}
impl<'a> Deref for Footer<'a> {
type Target = [u8];
fn deref(&self) -> &'a Self::Target {
self.0.as_bytes()
}
}
impl AsRef<str> for Footer<'_> {
fn as_ref(&self) -> &str {
self.0
}
}
impl<'a> From<&'a str> for Footer<'a> {
fn from(s: &'a str) -> Self {
Self(s)
}
}
impl fmt::Display for Footer<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl PartialEq for Footer<'_> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Footer<'_> {}
impl Footer<'_> {
pub fn try_from_token(token: &str) -> Result<Option<String>, PasetoError> {
let untrusted = UntrustedToken::try_parse(token)?;
untrusted.footer_str()
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
fn test_v2_footer() {
let footer = Footer::default();
assert_eq!(footer.as_ref(), "");
assert!(footer.as_ref().is_empty());
}
#[test]
fn test_set_v2_footer() {
let footer: Footer = "wubbulubbadubdub".into();
assert_eq!(footer.as_ref(), "wubbulubbadubdub");
assert!(!footer.as_ref().is_empty());
}
#[test]
fn test_try_from_token_with_footer() {
let token = "v4.local.payload.Zm9vdGVy"; let footer_str = Footer::try_from_token(token)
.expect("failed to extract footer")
.expect("footer should be present");
assert_eq!(&footer_str, "footer");
}
#[test]
fn test_try_from_token_without_footer() {
let token = "v4.local.payload";
let footer_opt = Footer::try_from_token(token).expect("should not error");
assert!(footer_opt.is_none());
}
#[test]
fn test_try_from_token_invalid_format() {
let token = "v4.local"; let result = Footer::try_from_token(token);
assert!(matches!(result, Err(PasetoError::IncorrectSize)));
}
}