use std::fmt;
use std::sync::Arc;
use super::Ed25519PrivateKey;
pub struct ClientCredentialsConfig {
pub client_id: String,
pub private_key: Ed25519PrivateKey,
pub certificate_id: Option<String>,
}
impl ClientCredentialsConfig {
pub fn new(client_id: impl Into<String>, private_key: Ed25519PrivateKey) -> Self {
Self {
client_id: client_id.into(),
private_key,
certificate_id: None,
}
}
#[must_use]
pub fn with_certificate_id(mut self, certificate_id: impl Into<String>) -> Self {
self.certificate_id = Some(certificate_id.into());
self
}
}
impl fmt::Debug for ClientCredentialsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ClientCredentialsConfig")
.field("client_id", &self.client_id)
.field("private_key", &"[REDACTED]")
.field("certificate_id", &self.certificate_id)
.finish()
}
}
#[derive(Clone)]
pub struct BearerCredentialsConfig {
token: Arc<str>,
}
impl BearerCredentialsConfig {
pub fn new(token: impl Into<String>) -> Self {
Self {
token: Arc::from(token.into()),
}
}
pub fn token(&self) -> &str {
&self.token
}
}
impl fmt::Debug for BearerCredentialsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BearerCredentialsConfig")
.field("token", &"[REDACTED]")
.finish()
}
}
impl<S: Into<String>> From<S> for BearerCredentialsConfig {
fn from(token: S) -> Self {
Self::new(token)
}
}
pub enum Credentials {
ClientCredentials(Box<ClientCredentialsConfig>),
Bearer(BearerCredentialsConfig),
}
impl Credentials {
pub fn is_client_credentials(&self) -> bool {
matches!(self, Credentials::ClientCredentials(_))
}
pub fn is_bearer(&self) -> bool {
matches!(self, Credentials::Bearer(_))
}
pub fn as_client_credentials(&self) -> Option<&ClientCredentialsConfig> {
match self {
Credentials::ClientCredentials(config) => Some(config),
_ => None,
}
}
pub fn as_bearer(&self) -> Option<&BearerCredentialsConfig> {
match self {
Credentials::Bearer(config) => Some(config),
_ => None,
}
}
}
impl fmt::Debug for Credentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Credentials::ClientCredentials(config) => {
f.debug_tuple("ClientCredentials").field(config).finish()
}
Credentials::Bearer(config) => f.debug_tuple("Bearer").field(config).finish(),
}
}
}
impl From<ClientCredentialsConfig> for Credentials {
fn from(config: ClientCredentialsConfig) -> Self {
Credentials::ClientCredentials(Box::new(config))
}
}
impl From<BearerCredentialsConfig> for Credentials {
fn from(config: BearerCredentialsConfig) -> Self {
Credentials::Bearer(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_client_credentials_new() {
let key = Ed25519PrivateKey::generate();
let config = ClientCredentialsConfig::new("test_client", key);
assert_eq!(config.client_id, "test_client");
assert!(config.certificate_id.is_none());
}
#[test]
fn test_client_credentials_with_certificate() {
let key = Ed25519PrivateKey::generate();
let config =
ClientCredentialsConfig::new("test_client", key).with_certificate_id("cert_123");
assert_eq!(config.certificate_id, Some("cert_123".to_string()));
}
#[test]
fn test_client_credentials_debug() {
let key = Ed25519PrivateKey::generate();
let config = ClientCredentialsConfig::new("test_client", key);
let debug = format!("{:?}", config);
assert!(debug.contains("test_client"));
assert!(debug.contains("REDACTED"));
}
#[test]
fn test_bearer_credentials_new() {
let config = BearerCredentialsConfig::new("test_token");
assert_eq!(config.token(), "test_token");
}
#[test]
fn test_bearer_credentials_debug() {
let config = BearerCredentialsConfig::new("secret_token");
let debug = format!("{:?}", config);
assert!(!debug.contains("secret_token"));
assert!(debug.contains("REDACTED"));
}
#[test]
fn test_bearer_credentials_clone() {
let config = BearerCredentialsConfig::new("test_token");
let cloned = config.clone();
assert_eq!(cloned.token(), "test_token");
}
#[test]
fn test_credentials_from_client_credentials() {
let key = Ed25519PrivateKey::generate();
let config = ClientCredentialsConfig::new("client", key);
let creds: Credentials = config.into();
assert!(creds.is_client_credentials());
assert!(!creds.is_bearer());
}
#[test]
fn test_credentials_from_bearer() {
let config = BearerCredentialsConfig::new("token");
let creds: Credentials = config.into();
assert!(creds.is_bearer());
assert!(!creds.is_client_credentials());
}
#[test]
fn test_credentials_as_methods() {
let key = Ed25519PrivateKey::generate();
let client_creds: Credentials = ClientCredentialsConfig::new("client", key).into();
assert!(client_creds.as_client_credentials().is_some());
assert!(client_creds.as_bearer().is_none());
let bearer_creds: Credentials = BearerCredentialsConfig::new("token").into();
assert!(bearer_creds.as_bearer().is_some());
assert!(bearer_creds.as_client_credentials().is_none());
}
#[test]
fn test_bearer_from_string() {
let config: BearerCredentialsConfig = "test_token".into();
assert_eq!(config.token(), "test_token");
let config: BearerCredentialsConfig = String::from("owned_token").into();
assert_eq!(config.token(), "owned_token");
}
#[test]
fn test_credentials_debug_client_credentials() {
let key = Ed25519PrivateKey::generate();
let creds: Credentials = ClientCredentialsConfig::new("client_id", key).into();
let debug = format!("{:?}", creds);
assert!(debug.contains("ClientCredentials"));
assert!(debug.contains("client_id"));
assert!(debug.contains("REDACTED"));
}
#[test]
fn test_credentials_debug_bearer() {
let creds: Credentials = BearerCredentialsConfig::new("secret").into();
let debug = format!("{:?}", creds);
assert!(debug.contains("Bearer"));
assert!(debug.contains("REDACTED"));
assert!(!debug.contains("secret"));
}
}