#[cfg(feature = "internal")]
use crate::config::ClientConfig;
use crate::transport::ResolvedCredential;
use secrecy::ExposeSecret;
use sha2::{Digest, Sha256};
#[cfg(feature = "internal")]
use wyrd_spec::error::WyrdError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SinkKind {
Record,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClientScope {
server_url: String,
credential_fingerprint: String,
}
impl ClientScope {
#[cfg(feature = "internal")]
pub fn from_config(config: &ClientConfig) -> Result<Self, WyrdError> {
let credential = config.resolve_credential().map_err(WyrdError::from)?;
Ok(Self {
server_url: config.http.base_url.trim_end_matches('/').to_owned(),
credential_fingerprint: fingerprint_credential(&credential),
})
}
#[must_use]
pub(crate) fn from_client(client: &crate::WyrdClient) -> Self {
let auth = &client.auth;
Self {
server_url: auth.base_url().trim_end_matches('/').to_owned(),
credential_fingerprint: fingerprint_credential(auth.credential()),
}
}
#[must_use]
#[cfg(feature = "internal")]
pub fn server_url(&self) -> &str {
&self.server_url
}
#[must_use]
#[cfg(feature = "internal")]
pub fn credential_fingerprint(&self) -> &str {
&self.credential_fingerprint
}
}
fn fingerprint_credential(credential: &ResolvedCredential) -> String {
let mut hasher = Sha256::new();
match credential {
ResolvedCredential::Renewable(source) => hasher.update(source.identity()),
ResolvedCredential::BearerToken(token) => hasher.update(token.expose_secret()),
ResolvedCredential::WorkloadJwt { jwt, .. } => hasher.update(jwt.expose_secret()),
ResolvedCredential::ApiKey(key) => hasher.update(key.expose_secret()),
ResolvedCredential::Delegated {
subject_token,
audience,
actor,
} => {
hasher.update(subject_token.expose_secret());
hasher.update(audience.as_str());
hasher.update(fingerprint_credential(actor.credential()));
}
}
hex::encode(hasher.finalize())
}