1use crate::reference::ReferenceXml;
4use crate::xml::{Access, AccessError, Xml};
5use crate::{
6 binding, certificate, commitment, container, counter, format, header, material, policy,
7 properties, renewed, role, timestamp, unsigned, validation,
8};
9use structured_asn1::memory::{MemoryError, OwnedVec, Work};
10use structured_ltv::baseline::ArchiveCensus;
11use structured_ltv::source::Location;
12
13mod uri;
14pub use uri::{UriError, UriResult, check_uris};
15mod fields;
16pub use fields::{FieldError, FieldResult, Fields, check_fields};
17
18#[derive(Debug)]
20pub enum Error<E, N> {
21 Container(container::ContainerError<E, N>),
23 Binding(binding::BindingError<E, N>),
25 Property(properties::Error<E, N>),
27 Format(format::CoverageError<E, N>),
29 Commitment(commitment::AssociationError<E, N>),
31 Timestamp(timestamp::InputError<E, N>),
33 Validation(validation::Error<E, N>),
35 Access(AccessError<E, N>),
37 Resource {
39 signature: N,
41 cause: MemoryError,
43 },
44}
45
46pub struct Preparation<N, D, G> {
51 requirements: unsigned::Requirements,
52 bound: binding::Bound<N, D, G>,
53 signed: properties::Signed<N, D, G>,
54 header: header::Header<N, D, G>,
55 certificates: certificate::References<N, D, G>,
56 formats: OwnedVec<format::CoveredFormat<N, D, G>>,
57 commitments: OwnedVec<commitment::Association<N, D, G>>,
58 roles: Option<role::Roles<N, D, G>>,
59 policy: Option<policy::Reading<N, D, G>>,
60 policy_store: Option<policy::Store<N, D, G>>,
61 unsigned: unsigned::Catalogue<N, D, G>,
62 timestamps: OwnedVec<timestamp::Stamp<N, D, G>>,
63 material: OwnedVec<material::Catalogue<N, D, G>>,
64 validation: OwnedVec<validation::Data<N, D, G>>,
65 renewed: OwnedVec<renewed::Catalogue<N, D, G>>,
66 references: OwnedVec<validation::ReferenceProperty<N, D, G>>,
67}
68
69impl<N, D, G> Preparation<N, D, G> {
70 #[must_use]
73 pub fn requirements(&self) -> unsigned::Requirements {
74 self.requirements
75 }
76 #[must_use]
78 pub fn bound(&self) -> &binding::Bound<N, D, G> {
79 &self.bound
80 }
81 #[must_use]
83 pub fn signed(&self) -> &properties::Signed<N, D, G> {
84 &self.signed
85 }
86 #[must_use]
88 pub fn header(&self) -> &header::Header<N, D, G> {
89 &self.header
90 }
91 #[must_use]
93 pub fn certificates(&self) -> &certificate::References<N, D, G> {
94 &self.certificates
95 }
96 #[must_use]
99 pub fn formats(&self) -> &[format::CoveredFormat<N, D, G>] {
100 &self.formats
101 }
102 #[must_use]
105 pub fn commitments(&self) -> &[commitment::Association<N, D, G>] {
106 &self.commitments
107 }
108 #[must_use]
110 pub fn roles(&self) -> Option<&role::Roles<N, D, G>> {
111 self.roles.as_ref()
112 }
113 #[must_use]
115 pub fn policy(&self) -> Option<&policy::Reading<N, D, G>> {
116 self.policy.as_ref()
117 }
118 #[must_use]
121 pub fn policy_store(&self) -> Option<&policy::Store<N, D, G>> {
122 self.policy_store.as_ref()
123 }
124 #[must_use]
126 pub fn unsigned(&self) -> &unsigned::Catalogue<N, D, G> {
127 &self.unsigned
128 }
129 #[must_use]
131 pub fn timestamps(&self) -> &[timestamp::Stamp<N, D, G>] {
132 &self.timestamps
133 }
134 #[must_use]
136 pub fn material(&self) -> &[material::Catalogue<N, D, G>] {
137 &self.material
138 }
139 #[must_use]
141 pub fn validation(&self) -> &[validation::Data<N, D, G>] {
142 &self.validation
143 }
144 #[must_use]
147 pub fn renewed(&self) -> &[renewed::Catalogue<N, D, G>] {
148 &self.renewed
149 }
150 #[must_use]
154 pub fn validation_references(&self) -> &[validation::ReferenceProperty<N, D, G>] {
155 &self.references
156 }
157}
158
159impl<N: Copy, D: Copy, G: Copy> ArchiveCensus for Preparation<N, D, G> {
160 type Id = N;
161 type Document = D;
162 type Generation = G;
163
164 fn signature(&self) -> Location<N, D, G> {
165 let layout = self.bound.containers();
166 Location {
167 snapshot: layout.snapshot(),
168 node: layout.signature(),
169 }
170 }
171 fn timestamps(&self) -> usize {
172 self.timestamps.len()
173 }
174 fn archive(&self, ordinal: usize) -> Option<N> {
175 let stamp = &self.timestamps[ordinal];
176 (stamp.role() == timestamp::Role::Archive).then(|| stamp.node())
177 }
178}
179
180pub type Prepared<X> = Preparation<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
183
184pub type PrepareResult<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
186
187pub fn prepare<X: ReferenceXml, W: Work>(
192 access: &Access<'_, X, W>,
193 signature: X::Id,
194 requirements: unsigned::Requirements,
195 counter: Option<&counter::Binding<X>>,
196) -> PrepareResult<Prepared<X>, X> {
197 let layout = container::locate(access, signature).map_err(Error::Container)?;
198 let bound = binding::bind(access, &layout).map_err(Error::Binding)?;
199 let header = header::read(access, &bound).map_err(Error::Property)?;
200 let signed = properties::read(access, &bound).map_err(Error::Property)?;
201 let certificates = certificate::read(access, &signed).map_err(Error::Property)?;
202 let roles = role::read(access, &signed).map_err(Error::Property)?;
203 let policy = policy::read(access, &signed).map_err(Error::Property)?;
204 let unsigned = unsigned::read(access, &bound, requirements).map_err(Error::Property)?;
205 let policy_store =
206 policy::read_store(access, &unsigned, policy.as_ref()).map_err(Error::Property)?;
207 unsigned::check_credential_material(access, &unsigned, roles.as_ref())
208 .map_err(Error::Property)?;
209 let formats =
210 format::check_references(access, &bound, &signed, counter).map_err(Error::Format)?;
211 let mut commitments = access
212 .query(signature, |_, _, work| Ok(work.vector()))
213 .map_err(Error::Access)?;
214 let mut timestamps = access
215 .query(signature, |_, _, work| Ok(work.vector()))
216 .map_err(Error::Access)?;
217 let mut material = access
218 .query(signature, |_, _, work| Ok(work.vector()))
219 .map_err(Error::Access)?;
220 let mut validation = access
221 .query(signature, |_, _, work| Ok(work.vector()))
222 .map_err(Error::Access)?;
223 let mut renewed = access
224 .query(signature, |_, _, work| Ok(work.vector()))
225 .map_err(Error::Access)?;
226 let mut references = access
227 .query(signature, |_, _, work| Ok(work.vector()))
228 .map_err(Error::Access)?;
229 let refusal = |cause| Error::Resource { signature, cause };
230 for index in 0..unsigned.entries().len() {
231 admit(access, signature)?;
232 let entry = unsigned.entries()[index];
233 match entry.role {
234 unsigned::Role::SignatureTimestamp
235 | unsigned::Role::Archive
236 | unsigned::Role::SignatureAndReferencesTimestamp
237 | unsigned::Role::ReferencesTimestamp => {
238 let stamp =
239 timestamp::read(access, &bound, entry.node).map_err(Error::Timestamp)?;
240 timestamps.try_push(stamp).map_err(refusal)?;
241 }
242 unsigned::Role::Certificates
243 | unsigned::Role::Revocation
244 | unsigned::Role::AttributeCertificates
245 | unsigned::Role::AttributeRevocation => {
246 let values = material::read(access, entry.node).map_err(Error::Property)?;
247 material.try_push(values).map_err(refusal)?;
248 }
249 unsigned::Role::AnyValidation | unsigned::Role::TimestampValidation => {
250 let values =
251 validation::read(access, &bound, entry.node).map_err(Error::Validation)?;
252 validation.try_push(values).map_err(refusal)?;
253 }
254 unsigned::Role::RenewedDigests => {
255 let values = renewed::read(access, &unsigned, index).map_err(Error::Property)?;
256 renewed.try_push(values).map_err(refusal)?;
257 }
258 unsigned::Role::CertificateReferences
259 | unsigned::Role::RevocationReferences
260 | unsigned::Role::AttributeCertificateReferences
261 | unsigned::Role::AttributeRevocationReferences => {
262 let values = validation::read_references(access, signature, entry)
263 .map_err(Error::Property)?;
264 references.try_push(values).map_err(refusal)?;
265 }
266 _ => {} }
268 }
269 signed_objects(access, &bound, &signed, &mut timestamps, &mut commitments)?;
270 Ok(Preparation {
271 requirements,
272 bound,
273 signed,
274 header,
275 certificates,
276 formats,
277 commitments: commitments.into_owned(),
278 roles,
279 policy,
280 policy_store,
281 unsigned,
282 timestamps: timestamps.into_owned(),
283 material: material.into_owned(),
284 validation: validation.into_owned(),
285 renewed: renewed.into_owned(),
286 references: references.into_owned(),
287 })
288}
289
290fn admit<X: Xml, W: Work>(access: &Access<'_, X, W>, signature: X::Id) -> PrepareResult<(), X> {
291 access
292 .query(signature, |_, _, work| Ok(work.charge_work(1)))
293 .map_err(Error::Access)?
294 .map_err(|cause| Error::Resource { signature, cause })
295}
296
297fn signed_objects<X: ReferenceXml, W: Work>(
298 access: &Access<'_, X, W>,
299 bound: &binding::Selected<X>,
300 signed: &properties::Reading<X>,
301 timestamps: &mut OwnedVec<timestamp::Timestamp<X>, W>,
302 commitments: &mut OwnedVec<commitment::Prepared<X>, W>,
303) -> PrepareResult<(), X> {
304 let Some(objects) = signed.data_objects() else {
305 return Ok(());
306 };
307 for index in 0..objects.entries().len() {
308 admit(access, signed.signature())?;
309 let entry = objects.entries()[index];
310 if entry.role == properties::DataObjectRole::Commitment {
311 let value =
312 commitment::prepare(access, bound, signed, index).map_err(Error::Commitment)?;
313 commitments
314 .try_push(value)
315 .map_err(|cause| Error::Resource {
316 signature: signed.signature(),
317 cause,
318 })?;
319 continue;
320 }
321 let stamp = match entry.role {
322 properties::DataObjectRole::AllTimestamp => {
323 timestamp::read_all_data_objects(access, bound, signed, entry.node)
324 }
325 properties::DataObjectRole::IndividualTimestamp => {
326 timestamp::read_individual_data_objects(access, bound, signed, entry.node)
327 }
328 _ => continue,
329 }
330 .map_err(Error::Timestamp)?;
331 timestamps
332 .try_push(stamp)
333 .map_err(|cause| Error::Resource {
334 signature: signed.signature(),
335 cause,
336 })?;
337 }
338 Ok(())
339}