use std::marker::PhantomData;
use crate::crypto::{CryptoProvider, sign};
use crate::errors::{ErrorKind, Result, new_error};
use crate::serialization::{DecodedJwtPartClaims, b64_encode_part};
use crate::validation::validate;
use crate::{DecodingKey, EncodingKey, Header, TokenData, Validation};
use crate::decoding::verify_signature_body;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Jws<C> {
pub protected: String,
pub payload: String,
pub signature: String,
#[serde(skip)]
pub _pd: PhantomData<C>,
}
pub fn encode<T: Serialize>(
header: &Header,
claims: Option<&T>,
key: &EncodingKey,
) -> Result<Jws<T>> {
if key.family() != header.alg.family() {
return Err(new_error(ErrorKind::InvalidAlgorithm));
}
let encoded_header = b64_encode_part(header)?;
let encoded_claims = match claims {
Some(claims) => b64_encode_part(claims)?,
None => "".to_string(),
};
let message = [encoded_header.as_str(), encoded_claims.as_str()].join(".");
let signature = sign(message.as_bytes(), key, header.alg)?;
Ok(Jws {
protected: encoded_header,
payload: encoded_claims,
signature,
_pd: Default::default(),
})
}
pub fn decode<T: DeserializeOwned>(
jws: &Jws<T>,
key: &DecodingKey,
validation: &Validation,
) -> Result<TokenData<T>> {
let header = Header::from_encoded(&jws.protected)?;
let message = [jws.protected.as_str(), jws.payload.as_str()].join(".");
let verifying_provider = (CryptoProvider::get_default().verifier_factory)(&header.alg, key)?;
verify_signature_body(
message.as_bytes(),
jws.signature.as_bytes(),
&header,
validation,
verifying_provider,
)?;
let decoded_claims = DecodedJwtPartClaims::from_jwt_part_claims(&jws.payload)?;
let claims = decoded_claims.deserialize()?;
validate(decoded_claims.deserialize()?, validation)?;
Ok(TokenData { header, claims })
}