1use crate::{
4 material::Placement,
5 query::Query,
6 range::RangeSource,
7 timestamp::{Node, Pades, Requirements},
8};
9use structured_asn1::memory::{MemoryError, OwnedVec, Work};
10use structured_ltv::{
11 baseline::ArchiveMaterial,
12 material::ParticipantMaterial,
13 source::{Location, Query as _, ScopeError},
14 timestamp::TimestampScope,
15};
16
17pub type Seal<'a, 'cl, 'r, 'v, 'c, 'd, 'auth, D, G, C> = ArchiveMaterial<
19 'a,
20 ParticipantMaterial<'cl, 'r, 'v, 'c, 'd, Node, D, G, Placement, Pades>,
21 crate::material::credentials::Report<'auth, C, D, G>,
22>;
23
24pub type SealReports<'s, 'a, 'cl, 'r, 'v, 'c, 'd, 'auth, D, G, C> =
26 &'s [Option<&'s Seal<'a, 'cl, 'r, 'v, 'c, 'd, 'auth, D, G, C>>];
27
28pub type SealsOf<'s, 'a, 'cl, 'r, 'v, 'c, 'd, 'auth, D, G, C> =
30 Seals<'s, Seal<'a, 'cl, 'r, 'v, 'c, 'd, 'auth, D, G, C>, D, G>;
31
32pub struct Seals<'s, R, D, G> {
37 pub(super) sources: OwnedVec<Occurrence<D, G>>,
38 pub(super) reports: &'s [Option<&'s R>],
39 pub(super) required: &'s structured_ltv::timestamp::TimestampRequirements<Node, D, G, Pades>,
40 pub(super) session: &'s crate::Session,
41 pub(super) vri_revisions: OwnedVec<usize>,
42}
43pub(super) struct Occurrence<D, G> {
44 pub(super) location: Location<Node, D, G>,
45 pub(super) revision: Option<usize>,
46}
47impl<'s, R, D: Copy, G: Copy> Seals<'s, R, D, G> {
48 #[must_use]
50 pub fn len(&self) -> usize {
51 self.sources.len()
52 }
53 #[must_use]
55 pub fn is_empty(&self) -> bool {
56 self.sources.is_empty()
57 }
58 #[must_use]
60 pub fn source(&self, ordinal: usize) -> Option<Location<Node, D, G>> {
61 self.sources.get(ordinal).map(|source| source.location)
62 }
63 #[must_use]
65 pub fn revision(&self, ordinal: usize) -> Option<usize> {
66 self.sources.get(ordinal).and_then(|source| source.revision)
67 }
68 #[must_use]
71 pub fn report(&self, ordinal: usize) -> Option<&'s R> {
72 self.reports.get(ordinal).copied().flatten()
73 }
74}
75
76#[derive(Debug)]
78pub enum Error {
79 Foreign {
81 node: Node,
83 },
84 Scope(ScopeError<Node>),
86 Resource {
88 node: Node,
90 cause: MemoryError,
92 },
93}
94
95pub fn seals<'s, 'a, 'cl, 'r, 'v, 'c, 'd, 'auth, C, S: RangeSource>(
100 required: &'s Requirements<'_, '_, S::Document, S::Generation>,
101 reports: SealReports<'s, 'a, 'cl, 'r, 'v, 'c, 'd, 'auth, S::Document, S::Generation, C>,
102 query: &Query<'_, '_, S>,
103) -> Result<SealsOf<'s, 'a, 'cl, 'r, 'v, 'c, 'd, 'auth, S::Document, S::Generation, C>, Error> {
104 let root = required.all().signature();
105 query.admit(root, 1).map_err(Error::Scope)?;
106 if !query.belongs(required.signature().owner().value.session)
107 || required.revision().is_some()
108 || reports.len() != required.document_timestamps().len()
109 {
110 return Err(Error::Foreign { node: root });
111 }
112 let mut sources = query.execution().vector();
113 sources
114 .try_reserve_exact(reports.len())
115 .map_err(|cause| Error::Resource { node: root, cause })?;
116 for (source, report) in required.document_timestamps().iter().zip(reports) {
117 query.admit(root, 1).map_err(Error::Scope)?;
118 let node = source.token();
119 if let Some(report) = report {
120 let actual = report.x509().inputs().requirements();
121 if actual.signature() != root
122 || !matches!(actual.scope(), TimestampScope::BeforeArchive(location)
123 if location.snapshot == query.snapshot() && location.node == node)
124 {
125 return Err(Error::Foreign { node });
126 }
127 }
128 let revision = source
129 .signature()
130 .and_then(|signature| match signature.coverage() {
131 crate::signature::Coverage::Revision(revision) => Some(revision),
132 crate::signature::Coverage::Partial => None,
133 });
134 sources
135 .try_push(Occurrence {
136 location: Location {
137 snapshot: query.snapshot(),
138 node,
139 },
140 revision,
141 })
142 .map_err(|cause| Error::Resource { node, cause })?;
143 }
144 query.admit(root, 1).map_err(Error::Scope)?;
145 let mut vri_revisions = query.execution().vector();
146 for source in required.vri_timestamps() {
147 query.admit(root, 1).map_err(Error::Scope)?;
148 vri_revisions
149 .try_push(source.revision)
150 .map_err(|cause| Error::Resource { node: root, cause })?;
151 }
152 Ok(Seals {
153 sources: sources.into_owned(),
154 reports,
155 required: required.all(),
156 session: required.signature().owner().value.session,
157 vri_revisions: vri_revisions.into_owned(),
158 })
159}