use std::fmt;
use crate::error::ErrorKind;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct IdTokenAudience(String);
impl IdTokenAudience {
pub fn new(audience: impl Into<String>) -> Self {
Self(audience.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for IdTokenAudience {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ServiceAccountEmail(String);
impl ServiceAccountEmail {
pub fn new(email: impl Into<String>) -> Self {
Self(email.into())
}
pub(crate) fn from_impersonation_url(url: &str) -> crate::error::Result<Self> {
let resource = url.rsplit('/').next().unwrap_or_default();
let email = resource.split(':').next().unwrap_or_default();
if email.is_empty() {
Err(ErrorKind::InvalidImpersonationUrl(url.to_string()).into())
} else {
Ok(Self::new(email))
}
}
}
impl fmt::Display for ServiceAccountEmail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn impersonation_url_names_the_service_account_before_the_method() {
let url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/invoker@orders.iam.gserviceaccount.com:generateAccessToken";
assert_eq!(
ServiceAccountEmail::from_impersonation_url(url).unwrap(),
ServiceAccountEmail::new("invoker@orders.iam.gserviceaccount.com")
);
}
#[test]
fn impersonation_url_without_a_service_account_is_invalid() {
let url =
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/:generateAccessToken";
assert!(matches!(
ServiceAccountEmail::from_impersonation_url(url)
.unwrap_err()
.into_kind(),
ErrorKind::InvalidImpersonationUrl(_)
));
}
}