use auths_verifier::IdentityDID;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Deserializer, Serialize};
use super::error::FederationError;
fn non_empty(raw: String, what: &'static str) -> Result<String, FederationError> {
if raw.trim().is_empty() {
return Err(FederationError::InvalidId(format!(
"{what} must not be empty"
)));
}
Ok(raw)
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct IdpId(String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct GroupId(String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Nonce(String);
macro_rules! string_newtype {
($ty:ident, $what:literal) => {
impl $ty {
#[doc = concat!("let id = ", stringify!($ty), "::new(\"value\")?;")]
pub fn new(value: impl Into<String>) -> Result<Self, FederationError> {
Ok(Self(non_empty(value.into(), $what)?))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = String::deserialize(deserializer)?;
non_empty(raw, $what)
.map($ty)
.map_err(serde::de::Error::custom)
}
}
};
}
string_newtype!(IdpId, "idp id");
string_newtype!(GroupId, "group id");
string_newtype!(Nonce, "nonce");
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LifecycleClaim {
Employed,
GroupMember(GroupId),
Suspended,
Terminated,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttestationContent {
pub subject: IdentityDID,
pub idp: IdpId,
pub claim: LifecycleClaim,
pub nonce: Nonce,
pub expires_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IdpAttestation {
#[serde(flatten)]
pub content: AttestationContent,
pub anchored_at_seq: u128,
}