use std::fmt::{self, Debug, Formatter};
use jsonwebtoken::errors::Error as JwtError;
use jsonwebtoken::{Algorithm, DecodingKey, TokenData, Validation, decode};
use salvo_core::Depot;
use serde::Deserialize;
pub trait JwtAuthDecoder {
type Error: std::error::Error + Send + Sync + 'static;
fn decode<C>(
&self,
token: &str,
depot: &mut Depot,
) -> impl Future<Output = Result<TokenData<C>, Self::Error>> + Send
where
C: for<'de> Deserialize<'de> + Clone;
}
pub struct ConstDecoder {
decoding_key: DecodingKey,
validation: Validation,
}
impl Debug for ConstDecoder {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ConstDecoder")
.field("validation", &self.validation)
.finish()
}
}
impl ConstDecoder {
#[must_use]
pub fn new(decoding_key: DecodingKey) -> Self {
Self::with_validation(decoding_key, Validation::default())
}
#[must_use]
pub fn with_validation(decoding_key: DecodingKey, validation: Validation) -> Self {
Self {
decoding_key,
validation,
}
}
#[must_use]
pub fn from_secret(secret: &[u8]) -> Self {
Self::with_validation(
DecodingKey::from_secret(secret),
Validation::new(Algorithm::HS256),
)
}
pub fn from_base64_secret(secret: &str) -> Result<Self, JwtError> {
DecodingKey::from_base64_secret(secret)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::HS256)))
}
pub fn from_rsa_pem(key: &[u8]) -> Result<Self, JwtError> {
DecodingKey::from_rsa_pem(key)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::RS256)))
}
pub fn from_rsa_components(modulus: &str, exponent: &str) -> Result<Self, JwtError> {
DecodingKey::from_rsa_components(modulus, exponent)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::RS256)))
}
#[must_use]
pub fn from_rsa_raw_components(modulus: &[u8], exponent: &[u8]) -> Self {
Self::with_validation(
DecodingKey::from_rsa_raw_components(modulus, exponent),
Validation::new(Algorithm::RS256),
)
}
pub fn from_ec_pem(key: &[u8]) -> Result<Self, JwtError> {
DecodingKey::from_ec_pem(key)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::ES256)))
}
pub fn from_ec_components(x: &str, y: &str) -> Result<Self, JwtError> {
DecodingKey::from_ec_components(x, y)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::ES256)))
}
pub fn from_ed_pem(key: &[u8]) -> Result<Self, JwtError> {
DecodingKey::from_ed_pem(key)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::EdDSA)))
}
#[must_use]
pub fn from_rsa_der(der: &[u8]) -> Self {
Self::with_validation(
DecodingKey::from_rsa_der(der),
Validation::new(Algorithm::RS256),
)
}
#[must_use]
pub fn from_ec_der(der: &[u8]) -> Self {
Self::with_validation(
DecodingKey::from_ec_der(der),
Validation::new(Algorithm::ES256),
)
}
#[must_use]
pub fn from_ed_der(der: &[u8]) -> Self {
Self::with_validation(
DecodingKey::from_ed_der(der),
Validation::new(Algorithm::EdDSA),
)
}
pub fn from_ed_components(x: &str) -> Result<Self, JwtError> {
DecodingKey::from_ed_components(x)
.map(|key| Self::with_validation(key, Validation::new(Algorithm::EdDSA)))
}
}
impl JwtAuthDecoder for ConstDecoder {
type Error = JwtError;
async fn decode<C>(&self, token: &str, _depot: &mut Depot) -> Result<TokenData<C>, Self::Error>
where
C: for<'de> Deserialize<'de> + Clone,
{
decode::<C>(token, &self.decoding_key, &self.validation)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rsa_raw_components_default_to_rs256() {
let decoder = ConstDecoder::from_rsa_raw_components(&[1, 2, 3], &[1, 0, 1]);
assert_eq!(decoder.validation.algorithms, [Algorithm::RS256]);
}
#[test]
fn secret_constructors_pin_hs256() {
let decoder = ConstDecoder::from_secret(b"secret");
assert_eq!(decoder.validation.algorithms, [Algorithm::HS256]);
let decoder = ConstDecoder::from_base64_secret("c2VjcmV0").unwrap();
assert_eq!(decoder.validation.algorithms, [Algorithm::HS256]);
}
}