1use super::{Placement, Unified};
4use crate::{
5 query::Query,
6 range::RangeSource,
7 timestamp::{Node, Pades},
8};
9use structured_ltv::{
10 baseline::X509Material,
11 material::{self, Incorporation, IncorporationError, IndexError},
12 pki::{self, ParticipantClosure, ParticipantRequirements, UsesError},
13 source::Query as _,
14 timestamp::TimestampScope,
15};
16
17pub struct Checks<'cl, 'r, 'v, 'c, 'd, D, G> {
20 inputs: &'cl ParticipantClosure<'r, 'v, 'c, 'd, Node, D, G, Pades>,
21 presence: Incorporation<'c, 'd, Node, D, G, Placement>,
22 source_conforming: bool,
23 revision: usize,
24}
25impl<'c, 'd, D: Copy, G: Copy> Checks<'_, '_, '_, 'c, 'd, D, G> {
26 #[must_use]
28 pub fn presence(&self) -> &Incorporation<'c, 'd, Node, D, G, Placement> {
29 &self.presence
30 }
31 #[must_use]
34 pub fn all_x509_requirements_met(&self) -> bool {
35 self.source_conforming && self.presence.all_present()
36 }
37 #[must_use]
40 pub fn revision(&self) -> usize {
41 self.revision
42 }
43}
44impl<'v, 'd, D: Copy, G: Copy> X509Material<'v, 'd> for Checks<'_, '_, 'v, '_, 'd, D, G> {
45 type Id = Node;
46 type Document = D;
47 type Generation = G;
48 type Issuer = Pades;
49 fn requirements(&self) -> &ParticipantRequirements<'v, 'd, Node, D, G, Pades> {
50 self.inputs.requirements()
51 }
52 fn all_x509_requirements_met(&self) -> bool {
53 Self::all_x509_requirements_met(self)
54 }
55}
56
57#[derive(Debug)]
59pub enum Error {
60 Scope,
62 Index(IndexError<Node>),
64 Uses(UsesError<Node>),
66 Presence(IncorporationError<Node>),
68}
69impl<D: Copy + Eq, G: Copy + Eq> Unified<'_, '_, D, G> {
70 pub fn check_participants<'cl, 'r, 'v, 'c, 'd, S: RangeSource<Document = D, Generation = G>>(
76 &self,
77 inputs: &'cl ParticipantClosure<'r, 'v, 'c, 'd, Node, D, G, Pades>,
78 paths: &structured_ltv::timestamp::TimestampPaths<'_, '_, '_, Node, D, G, Pades>,
79 query: &Query<'_, '_, S>,
80 ) -> Result<Checks<'cl, 'r, 'v, 'c, 'd, D, G>, Error> {
81 let required = inputs.requirements();
82 if !matches!(required.scope(), TimestampScope::All(_)) {
83 return Err(Error::Scope);
84 }
85 if !query.belongs(self.session)
86 || required.signature() != self.root
87 || required.scope().location().snapshot != query.snapshot()
88 {
89 return Err(Error::Index(IndexError::Foreign {
90 signature: self.root,
91 }));
92 }
93 query
94 .admit(self.root, 2)
95 .map_err(|cause| Error::Index(IndexError::Scope(cause)))?;
96 if !core::ptr::eq(paths.required(), self.required) || !required.same_timestamps(paths) {
97 return Err(Error::Scope);
98 }
99 self.index
100 .require_signature(self.root, query)
101 .map_err(Error::Index)?;
102 let uses = pki::authority_uses(inputs, query).map_err(Error::Uses)?;
103 let artifacts = material::artifact_uses(&uses, query).map_err(Error::Uses)?;
104 let presence =
105 material::incorporation(&artifacts, &self.index, query).map_err(Error::Presence)?;
106 Ok(Checks {
107 inputs,
108 presence,
109 source_conforming: self.complete,
110 revision: self.revision,
111 })
112 }
113
114 #[expect(
118 clippy::result_large_err,
119 reason = "the common participant archive error preserves original typed artifact failures and cannot allocate an envelope after refusal"
120 )]
121 pub fn archived_participants<'cl, 'r, 'v, 'c, 'd, S, W>(
122 &self,
123 inputs: &'cl ParticipantClosure<'r, 'v, 'c, 'd, Node, D, G, Pades>,
124 coverage: &material::Coverage<Node, D, G, W, Pades>,
125 actor: &structured_ltv::timestamp::CheckedActor<'_, '_, Node, D, G, Pades>,
126 query: &Query<'_, '_, S>,
127 ) -> Result<
128 material::ParticipantMaterial<'cl, 'r, 'v, 'c, 'd, Node, D, G, Placement, Pades>,
129 material::ParticipantArchiveError<Node>,
130 >
131 where
132 S: RangeSource<Document = D, Generation = G>,
133 W: structured_asn1::memory::Work,
134 {
135 if !query.belongs(self.session) || inputs.requirements().signature() != self.root {
136 return Err(material::ParticipantArchiveError::Foreign {
137 expected: self.root,
138 actual: inputs.requirements().signature(),
139 });
140 }
141 material::archived_participants(inputs, &self.index, coverage, actor.verified(), query)
142 }
143}