Skip to main content

heddle_api/v2/
invitation.rs

1//! Shape validation for the public invitation capability preview.
2
3use crate::heddle::api::v1alpha2::{InvitationResolution, invitation_resolution::Status};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
6pub enum InvitationResolutionError {
7    #[error("UNAVAILABLE invitation resolution contains disclosed details")]
8    UnavailableDetails,
9    #[error("inviter requires an already-public handle")]
10    InviterHandle,
11    #[error("agent label requires an inviter handle")]
12    AgentWithoutInviter,
13}
14
15/// Validate the wire-visible invitation preview before a client displays it.
16/// The server remains responsible for checking the secret and resolving the
17/// public handle, account lifecycle and agent label at read time.
18pub fn validate_invitation_resolution(
19    response: &InvitationResolution,
20) -> Result<(), InvitationResolutionError> {
21    if response.status == Status::Unavailable as i32
22        && (response.spool.is_some()
23            || !response.spool_name.is_empty()
24            || response.role != 0
25            || response.expires_at.is_some()
26            || response.inviter.is_some()
27            || !response.inviter_via_agent_label.is_empty())
28    {
29        return Err(InvitationResolutionError::UnavailableDetails);
30    }
31    if response
32        .inviter
33        .as_ref()
34        .is_some_and(|owner| owner.handle.is_empty())
35    {
36        return Err(InvitationResolutionError::InviterHandle);
37    }
38    if !response.inviter_via_agent_label.is_empty()
39        && !response
40            .inviter
41            .as_ref()
42            .is_some_and(|owner| !owner.handle.is_empty())
43    {
44        return Err(InvitationResolutionError::AgentWithoutInviter);
45    }
46    Ok(())
47}