pub struct TrustTask<P> {Show 13 fields
pub id: String,
pub thread_id: Option<String>,
pub parent_thread_id: Option<String>,
pub ceremony: Option<Ceremony>,
pub type_uri: TypeUri,
pub issuer: Option<String>,
pub recipient: Option<String>,
pub issued_at: Option<DateTime<Utc>>,
pub expires_at: Option<DateTime<Utc>>,
pub payload: P,
pub context: Option<JsonLdContext>,
pub proof: Option<Proof>,
pub extra: BTreeMap<String, Value>,
}Expand description
A single Trust Task document, per SPEC.md §4.2.
Field naming mirrors the wire form via #[serde(rename = ...)]. Unknown
top-level members are preserved in extra on round-trip so
that forwarding consumers honor the §7.1 producer guidance to preserve
unrecognized members.
Fields§
§id: StringThe document identifier — globally unique to this instance.
thread_id: Option<String>The thread identifier correlating this document with others in the same logical exchange (SPEC.md §4.9).
parent_thread_id: Option<String>The threadId of the exchange containing this one, where this exchange
is conducted inside another (SPEC.md §4.9.2).
A navigation aid. It records one level of containment and does not
change which exchange attests an event — §4.9.1 governs that, and holds
whether or not this member is present. Like thread_id it carries no
normative validation semantics: a consumer MUST NOT reject a document on
the basis of parentThreadId alone.
ceremony: Option<Ceremony>Records that this document is a step of a Trust Ceremony — a flow composed of several Trust Tasks (SPEC.md §4.11).
Optional in every sense: no specification declares anything about ceremonies, a document without it is fully conforming, and a consumer that does not implement ceremonies processes the document unchanged. Ignoring it is always safe, because §4.11.4 forbids deriving authority from it — there is nothing a ceremony-aware consumer may do that an unaware one omits.
type_uri: TypeUriThe Type URI identifying the specification and version this document conforms to.
issuer: Option<String>VID of the party responsible for the document’s content.
recipient: Option<String>VID of the party expected to act upon the document.
issued_at: Option<DateTime<Utc>>Timestamp recording when the document was produced (SPEC.md §4.2).
expires_at: Option<DateTime<Utc>>Timestamp after which the document is no longer valid (SPEC.md §4.2).
payload: PThe task-specific body, whose internal structure is defined by the
specification identified by type_uri.
context: Option<JsonLdContext>Optional JSON-LD context (SPEC.md §4.6). When present, the document MUST be processable as JSON-LD.
proof: Option<Proof>Optional Data Integrity proof binding the document to its issuer.
extra: BTreeMap<String, Value>Any additional top-level members carried by the document. Preserved on round-trip per the §7.1 / §7.2 guidance to retain unrecognized members.
Implementations§
Source§impl<P> TrustTask<P>
impl<P> TrustTask<P>
Sourcepub fn new(id: impl Into<String>, type_uri: TypeUri, payload: P) -> TrustTask<P>
pub fn new(id: impl Into<String>, type_uri: TypeUri, payload: P) -> TrustTask<P>
Construct a new document with only the required members populated. Optional members can be set via field assignment.
Sourcepub fn for_payload(id: impl Into<String>, payload: P) -> TrustTask<P>where
P: Payload,
pub fn for_payload(id: impl Into<String>, payload: P) -> TrustTask<P>where
P: Payload,
Construct a new document, taking the type URI from the payload’s
Payload impl. Saves callers from restating the Type URI when they
already hold a typed payload from crate::specs.
let req = TrustTask::for_payload("req-1", AclGrant { ... });
assert_eq!(req.type_uri, AclGrant::type_uri());Sourcepub fn enforce_audience_binding(&self) -> Result<(), RejectReason>where
P: Payload,
pub fn enforce_audience_binding(&self) -> Result<(), RejectReason>where
P: Payload,
Apply the SPEC.md §7.2 item 8 / §4.8.2 audience-binding rule: when
proof is present and recipient is absent in-band, reject the
document with malformed_request unless the originating
specification is a bearer specification (§4.8.3).
This check requires the payload type implement Payload so the
codegen-emitted Payload::IS_BEARER flag is reachable; callers
holding a TrustTask<serde_json::Value> should downcast via
crate::Dispatcher or by hand before invoking this method.
A non-bearer specification that signs every document with an
in-band recipient (which is the safe default) always passes this
check. A bearer specification opts out of audience binding at the
spec layer and always passes — bearer status is published in the
spec’s front matter and codegened into the Payload impl, not
chosen by the consumer.
Sourcepub fn enforce_spec_policy(&self) -> Result<(), RejectReason>where
P: Payload,
pub fn enforce_spec_policy(&self) -> Result<(), RejectReason>where
P: Payload,
Apply the per-spec consumer checks that depend on the payload type’s codegen-emitted flags — the typed subset of SPEC §7.2:
- item 5b — recipient-REQUIRED (
Payload::IS_RECIPIENT_REQUIRED): arecipient-REQUIRED spec needs the recipient carried in-band, so a document without one ismalformedRequest. - item 7 clause A — proof-REQUIRED (
Payload::IS_PROOF_REQUIRED): aproof-REQUIRED spec rejects a proofless document withproofRequired. - §7.3 item 17 — issuedAt-REQUIRED
(
Payload::IS_ISSUED_AT_REQUIRED): a specification defining a consequential Trust Task raises §4.2’sissuedAtSHOULD to a MUST for its own documents, so a document without one ismalformedRequest— the code §7.2 item 13 already uses for the freshness rejections, since §8.3 defines no dedicated one andexpiredwould misdescribe a document that was never acceptable. This is the specification’s requirement, not the consumer’s; seeFreshnessPolicy::require_issued_atfor the consumer-side counterpart, which is applied separately. - item 8 — audience binding (
Self::enforce_audience_binding).
This is the single source of truth for the flag-driven §7.2 checks. Both
the library consume_inbound path and any
binding-specific pipeline (for example the HTTPS server) call it, so the
two cannot diverge on the check set as new flag-driven rules are added.
It does not include the non-typed checks (expiry, recipient/transport
cross-check, proof verification), which each pipeline applies around
this call per its own transport model.
Sourcepub fn is_expired_at(&self, now: DateTime<Utc>) -> bool
pub fn is_expired_at(&self, now: DateTime<Utc>) -> bool
Returns true if expires_at is set and now ≥ expiresAt
(inclusive bound per SPEC.md §4.2). The instant expiresAt is
itself treated as expired, matching JWT-style semantics.
SPEC §4.2 permits a consumer to apply a small clock-skew tolerance
(typically ≤ 60s); apply that at the caller by adjusting now.
Sourcepub fn validate_basic(
&self,
now: DateTime<Utc>,
my_vid: &str,
) -> Result<(), RejectReason>
pub fn validate_basic( &self, now: DateTime<Utc>, my_vid: &str, ) -> Result<(), RejectReason>
Apply the framework-level rejection rules from SPEC.md §7.2 items 4 and 5:
- Item 4 — reject when
expiresAtis set andnow ≥ expiresAt(inclusive bound per the post-0.2 §4.2 wording). - Item 5 — reject when
recipientis set and does not identifymy_vid.
§⚠ This is not the full §7.2 check
A conforming consumer pipeline runs all six (now eight) items of §7.2. This method covers items 4 and 5 only:
| §7.2 item | What it checks | Where it lives |
|---|---|---|
| 1 | Framework schema validation | caller responsibility (e.g. serde + feature validate) |
| 2 | Payload schema validation | caller (typed TrustTask<P> + feature validate) |
| 3 | Unknown type URI | crate::Dispatcher / caller’s type registry |
| 4 | Expiry | validate_basic |
| 5 | Recipient mismatch | validate_basic |
| 6 | In-band vs transport identity | TransportHandler::resolve_parties |
| 7 | Proof handling (IS_PROOF_REQUIRED + verification policy) | consume_inbound + ProofVerifier (cryptosuite in a companion crate) |
| 8 | Audience binding (proof+no-recipient on non-bearer specs) | enforce_audience_binding |
The full §7.2 pipeline is bundled in
consume_inbound — items 4–8 in one
call. Direct use of validate_basic is for callers that have
their own composition.
Treat validate_basic(now, my_vid)? as stage 2 of a multi-stage
validation. Calling only this method on an inbound document
produces a non-conforming consumer.
Sourcepub fn reject_with(
&self,
id: impl Into<String>,
payload: impl Into<ErrorPayload>,
) -> TrustTask<ErrorPayload>
pub fn reject_with( &self, id: impl Into<String>, payload: impl Into<ErrorPayload>, ) -> TrustTask<ErrorPayload>
Build the trust-task-error response document for this request,
per the spec’s “Reporting consumer” conformance rules.
Wires:
type→https://trusttasks.org/spec/trust-task-error/0.1threadId→ this request’sthreadId, falling back to itsidper SPEC.md §4.9.issuer→ this request’srecipient(the rejecting consumer).recipient→ this request’sissuer(the original producer).issuedAt→Utc::now.
payload is taken as-is. Pass an ErrorPayload you constructed
directly, the output of ErrorPayload::from applied to a
RejectReason, or anything else that converts via Into.
The caller supplies id; the framework does not constrain its form
beyond uniqueness (SPEC.md §4.3). UUIDv4 is the recommended default.
§⚠ Identity-mismatch safety
This method copies request.issuer verbatim into the error
response’s recipient. Under most rejections (Expired,
ProofRequired, ProofInvalid, TaskFailed, …) the in-band
issuer is a value the consumer has reason to trust — for example,
because TransportHandler::resolve_parties
already accepted it. Under RejectReason::IdentityMismatch,
however, that in-band issuer is by definition the contested
identity and MUST NOT be addressed as the error response’s
recipient (SPEC.md §8.1, §10.4). For that case, use either
Self::reject_with_recipient with an explicit transport-
authenticated recipient, or
TransportHandler::reject,
which applies the §8.1 routing policy automatically.
Sourcepub fn reject_with_recipient(
&self,
id: impl Into<String>,
payload: impl Into<ErrorPayload>,
recipient: Option<String>,
) -> TrustTask<ErrorPayload>
pub fn reject_with_recipient( &self, id: impl Into<String>, payload: impl Into<ErrorPayload>, recipient: Option<String>, ) -> TrustTask<ErrorPayload>
Build the trust-task-error response document with an explicit
recipient. Use this when the safe default in Self::reject_with
does not apply — most importantly under
RejectReason::IdentityMismatch, where SPEC.md §8.1 requires the
response to address the transport-authenticated sender rather than
the in-band (contested) issuer.
recipient = None is conformant: SPEC.md §8.1 permits a consumer
faced with an identity_mismatch rejection and no transport-
authenticated sender to suppress the response entirely; the caller
can choose to drop the returned ErrorResponse in that case.
Sourcepub fn respond_with<R>(&self, id: impl Into<String>, payload: R) -> TrustTask<R>
pub fn respond_with<R>(&self, id: impl Into<String>, payload: R) -> TrustTask<R>
Build the success-response document for this request, per SPEC.md
§4.4.1. The mirror of reject_with for the
success path.
Wires:
type→ this request’s Type URI with#responsefragment.threadId→ this request’sthreadId, falling back to itsidper SPEC.md §4.9.issuer→ this request’srecipient(the responding party).recipient→ this request’sissuer(the original producer).issuedAt→Utc::now.
R is the response payload type defined by the originating Trust
Task specification’s $anchor: "response" sub-schema. A spec that
defines no success response is fire-and-forget; do not call this
method for such specs (SPEC.md §4.4.1).
Source§impl<P> TrustTask<P>
impl<P> TrustTask<P>
Sourcepub fn validate_freshness(
&self,
now: DateTime<Utc>,
policy: &FreshnessPolicy,
) -> Result<(), RejectReason>
pub fn validate_freshness( &self, now: DateTime<Utc>, policy: &FreshnessPolicy, ) -> Result<(), RejectReason>
Apply policy to this document’s issuedAt / expiresAt.
This is the freshness half of SPEC §7.2 item 4 that
validate_basic does not cover.
consume_inbound calls it for you; call it
directly only if you compose the §7.2 pipeline by hand.
Checks, in order:
issuedAtbeyondnow + skew→malformedRequest. A document cannot have been produced after the moment it arrived.expiresAt <= issuedAt→malformedRequest. The document states a validity interval containing no valid instant.issuedAtabsent whileFreshnessPolicy::require_issued_at→malformedRequest.issuedAtolder thanmax_age + skew→expired.- Neither
issuedAtnorexpiresAt, under a policy that sets amax_age→expired. There is no window to place the document in.
Trait Implementations§
Source§impl<'de, P> Deserialize<'de> for TrustTask<P>where
P: Deserialize<'de>,
impl<'de, P> Deserialize<'de> for TrustTask<P>where
P: Deserialize<'de>,
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<TrustTask<P>, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<TrustTask<P>, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
Source§impl Display for TrustTask<ErrorPayload>
impl Display for TrustTask<ErrorPayload>
Source§impl Error for TrustTask<ErrorPayload>
impl Error for TrustTask<ErrorPayload>
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl<P> ProofExt for TrustTask<P>
impl<P> ProofExt for TrustTask<P>
Source§fn sign<'life0, 'life1, 'async_trait>(
&'life0 mut self,
signer: &'life1 dyn Signer,
options: SignOptions,
) -> Pin<Box<dyn Future<Output = Result<(), SignError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
TrustTask<P>: 'async_trait,
fn sign<'life0, 'life1, 'async_trait>(
&'life0 mut self,
signer: &'life1 dyn Signer,
options: SignOptions,
) -> Pin<Box<dyn Future<Output = Result<(), SignError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
TrustTask<P>: 'async_trait,
affinidi only.proof member. Read moreSource§impl<P> Serialize for TrustTask<P>where
P: Serialize,
impl<P> Serialize for TrustTask<P>where
P: Serialize,
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
impl<P> StructuralPartialEq for TrustTask<P>where
P: PartialEq,
Auto Trait Implementations§
impl<P> Freeze for TrustTask<P>where
P: Freeze,
impl<P> RefUnwindSafe for TrustTask<P>where
P: RefUnwindSafe,
impl<P> Send for TrustTask<P>where
P: Send,
impl<P> Sync for TrustTask<P>where
P: Sync,
impl<P> Unpin for TrustTask<P>where
P: Unpin,
impl<P> UnsafeUnpin for TrustTask<P>where
P: UnsafeUnpin,
impl<P> UnwindSafe for TrustTask<P>where
P: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> BorrowUnordered for T
impl<T> BorrowUnordered for T
fn as_unordered(&self) -> &Unordered<T>
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<'de, T, C> DeserializeTyped<'de, C> for Twhere
T: Deserialize<'de>,
impl<'de, T, C> DeserializeTyped<'de, C> for Twhere
T: Deserialize<'de>,
fn deserialize_typed<S>(
_: &C,
deserializer: S,
) -> Result<T, <S as Deserializer<'de>>::Error>where
S: Deserializer<'de>,
impl<T, U> DeserializeTypedOwned<T> for Uwhere
U: for<'de> DeserializeTyped<'de, T>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<T, U, C> IntoWithContext<U, C> for Twhere
U: FromWithContext<T, C>,
impl<T, U, C> IntoWithContext<U, C> for Twhere
U: FromWithContext<T, C>,
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> ResourceProvider<()> for T
impl<T> ResourceProvider<()> for T
Source§fn get_resource(&self) -> &()
fn get_resource(&self) -> &()
T.