use serde::Serialize;
use thiserror::Error;
use crate::document::{ErrorResponse, TrustTask};
use crate::error::RejectReason;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ResolvedParties {
pub issuer: Option<String>,
pub recipient: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TransportContext {
pub issuer: Option<String>,
pub recipient: Option<String>,
}
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum ConsistencyError {
#[error("in-band issuer {in_band:?} does not match transport-derived {transport:?}")]
IssuerMismatch {
in_band: String,
transport: String,
},
#[error("in-band recipient {in_band:?} does not match transport-derived {transport:?}")]
RecipientMismatch {
in_band: String,
transport: String,
},
}
pub trait TransportHandler {
fn binding_uri(&self) -> &str;
fn derive_parties(&self) -> TransportContext;
fn prepare_outbound<P: Serialize>(&self, _doc: &mut TrustTask<P>) {}
fn resolve_parties<P>(&self, doc: &TrustTask<P>) -> Result<ResolvedParties, ConsistencyError> {
let ctx = self.derive_parties();
let issuer = match (doc.issuer.as_deref(), ctx.issuer.as_deref()) {
(Some(in_band), Some(transport)) if in_band != transport => {
return Err(ConsistencyError::IssuerMismatch {
in_band: in_band.to_string(),
transport: transport.to_string(),
});
}
(Some(in_band), _) => Some(in_band.to_string()),
(None, Some(transport)) => Some(transport.to_string()),
(None, None) => None,
};
let recipient = match (doc.recipient.as_deref(), ctx.recipient.as_deref()) {
(Some(in_band), Some(transport)) if in_band != transport => {
return Err(ConsistencyError::RecipientMismatch {
in_band: in_band.to_string(),
transport: transport.to_string(),
});
}
(Some(in_band), _) => Some(in_band.to_string()),
(None, Some(transport)) => Some(transport.to_string()),
(None, None) => None,
};
Ok(ResolvedParties { issuer, recipient })
}
fn reject<P>(
&self,
doc: &TrustTask<P>,
id: impl Into<String>,
reason: RejectReason,
) -> Option<ErrorResponse> {
let recipient = match &reason {
RejectReason::IdentityMismatch(_) => {
let from_transport = self.derive_parties().issuer;
from_transport.as_ref()?;
from_transport
}
_ => doc.issuer.clone(),
};
Some(doc.reject_with_recipient(id, reason, recipient))
}
}