#[cfg(doctest)]
doctest!("../README.md");
use std::borrow::Cow;
#[cfg(doctest)]
use doc_comment::doctest;
use serde::{Deserialize, Serialize};
#[cfg(feature = "openssl")]
pub use crate::algorithm::openssl::PKeyWithDigest;
pub use crate::algorithm::store::Store;
pub use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
pub use crate::claims::Claims;
pub use crate::claims::RegisteredClaims;
pub use crate::error::Error;
pub use crate::header::{Header, JoseHeader};
pub use crate::token::signed::{SignWithKey, SignWithStore};
pub use crate::token::verified::{VerifyWithKey, VerifyWithStore};
pub use crate::token::{Unsigned, Unverified, Verified};
pub mod algorithm;
pub mod claims;
pub mod error;
pub mod header;
pub mod token;
const SEPARATOR: &str = ".";
pub struct Token<H, C, S> {
header: H,
claims: C,
signature: S,
}
impl<H, C, S> Token<H, C, S> {
pub fn header(&self) -> &H {
&self.header
}
pub fn claims(&self) -> &C {
&self.claims
}
pub fn remove_signature(self) -> Token<H, C, Unsigned> {
Token {
header: self.header,
claims: self.claims,
signature: Unsigned,
}
}
}
impl<H, C, S> Into<(H, C)> for Token<H, C, S> {
fn into(self) -> (H, C) {
(self.header, self.claims)
}
}
pub trait ToBase64 {
fn to_base64(&self) -> Result<Cow<str>, Error>;
}
impl<T: Serialize> ToBase64 for T {
fn to_base64(&self) -> Result<Cow<str>, Error> {
let json_bytes = serde_json::to_vec(&self)?;
let encoded_json_bytes = base64::encode_config(&json_bytes, base64::URL_SAFE_NO_PAD);
Ok(Cow::Owned(encoded_json_bytes))
}
}
pub trait FromBase64: Sized {
fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error>;
}
impl<T: for<'de> Deserialize<'de> + Sized> FromBase64 for T {
fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error> {
let json_bytes = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
Ok(serde_json::from_slice(&json_bytes)?)
}
}
#[cfg(test)]
mod tests {
use crate::algorithm::AlgorithmType::Hs256;
use crate::error::Error;
use crate::header::Header;
use crate::token::signed::SignWithKey;
use crate::token::verified::VerifyWithKey;
use crate::Claims;
use crate::Token;
use hmac::Hmac;
use hmac::NewMac;
use sha2::Sha256;
#[test]
pub fn raw_data() -> Result<(), Error> {
let raw = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let token: Token<Header, Claims, _> = Token::parse_unverified(raw)?;
assert_eq!(token.header.algorithm, Hs256);
let verifier: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
assert!(token.verify_with_key(&verifier).is_ok());
Ok(())
}
#[test]
pub fn roundtrip() -> Result<(), Error> {
let token: Token<Header, Claims, _> = Default::default();
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
let signed_token = token.sign_with_key(&key)?;
let signed_token_str = signed_token.as_str();
let recreated_token: Token<Header, Claims, _> = Token::parse_unverified(signed_token_str)?;
assert_eq!(signed_token.header(), recreated_token.header());
assert_eq!(signed_token.claims(), recreated_token.claims());
recreated_token.verify_with_key(&key)?;
Ok(())
}
}