openapi-nexus 0.1.16

OpenAPI 3.x multi-language code generator
Documentation
use std::sync::Arc;

/// Trait for authenticating requests.
pub trait Authenticator: Send + Sync + std::fmt::Debug {
    /// Return header key-value pairs to apply to the request.
    fn auth_headers(&self) -> Vec<(&str, String)>;
}

/// Bearer token authentication.
///
/// Use [`BearerAuth::new`] with a static token, or
/// [`BearerAuth::from_provider`] with a function that returns the
/// current token (evaluated on every request).
pub struct BearerAuth {
    token: TokenSource,
}

enum TokenSource {
    Static(String),
    Dynamic(Arc<dyn Fn() -> String + Send + Sync>),
}

impl std::fmt::Debug for TokenSource {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Static(t) => f.debug_tuple("Static").field(&t).finish(),
            Self::Dynamic(_) => f.debug_tuple("Dynamic").field(&"<function>").finish(),
        }
    }
}

impl Clone for TokenSource {
    fn clone(&self) -> Self {
        match self {
            Self::Static(t) => Self::Static(t.clone()),
            Self::Dynamic(f) => Self::Dynamic(Arc::clone(f)),
        }
    }
}

impl std::fmt::Debug for BearerAuth {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BearerAuth").field("token", &self.token).finish()
    }
}

impl Clone for BearerAuth {
    fn clone(&self) -> Self {
        Self {
            token: self.token.clone(),
        }
    }
}

impl BearerAuth {
    /// Create a new bearer token authenticator with a static token.
    pub fn new(token: impl Into<String>) -> Self {
        Self {
            token: TokenSource::Static(token.into()),
        }
    }

    /// Create a bearer token authenticator that evaluates the given
    /// function on every request to obtain the current token.
    pub fn from_provider(f: impl Fn() -> String + Send + Sync + 'static) -> Self {
        Self {
            token: TokenSource::Dynamic(Arc::new(f)),
        }
    }
}

impl Authenticator for BearerAuth {
    fn auth_headers(&self) -> Vec<(&str, String)> {
        let token = match &self.token {
            TokenSource::Static(t) => t.clone(),
            TokenSource::Dynamic(f) => f(),
        };
        vec![("Authorization", format!("Bearer {}", token))]
    }
}

/// API key authentication.
///
/// Use [`ApiKeyAuth::new`] with a static key, or
/// [`ApiKeyAuth::from_provider`] with a function that returns the
/// current key (evaluated on every request).
pub struct ApiKeyAuth {
    header_name: String,
    api_key: KeySource,
}

enum KeySource {
    Static(String),
    Dynamic(Arc<dyn Fn() -> String + Send + Sync>),
}

impl std::fmt::Debug for KeySource {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Static(k) => f.debug_tuple("Static").field(&k).finish(),
            Self::Dynamic(_) => f.debug_tuple("Dynamic").field(&"<function>").finish(),
        }
    }
}

impl Clone for KeySource {
    fn clone(&self) -> Self {
        match self {
            Self::Static(k) => Self::Static(k.clone()),
            Self::Dynamic(f) => Self::Dynamic(Arc::clone(f)),
        }
    }
}

impl std::fmt::Debug for ApiKeyAuth {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ApiKeyAuth")
            .field("header_name", &self.header_name)
            .field("api_key", &self.api_key)
            .finish()
    }
}

impl Clone for ApiKeyAuth {
    fn clone(&self) -> Self {
        Self {
            header_name: self.header_name.clone(),
            api_key: self.api_key.clone(),
        }
    }
}

impl ApiKeyAuth {
    /// Create a new API key authenticator with a static key.
    pub fn new(header_name: impl Into<String>, api_key: impl Into<String>) -> Self {
        Self {
            header_name: header_name.into(),
            api_key: KeySource::Static(api_key.into()),
        }
    }

    /// Create an API key authenticator that evaluates the given
    /// function on every request to obtain the current key.
    pub fn from_provider(
        header_name: impl Into<String>,
        f: impl Fn() -> String + Send + Sync + 'static,
    ) -> Self {
        Self {
            header_name: header_name.into(),
            api_key: KeySource::Dynamic(Arc::new(f)),
        }
    }
}

impl Authenticator for ApiKeyAuth {
    fn auth_headers(&self) -> Vec<(&str, String)> {
        let key = match &self.api_key {
            KeySource::Static(k) => k.clone(),
            KeySource::Dynamic(f) => f(),
        };
        vec![(&self.header_name, key)]
    }
}