1use crate::container::XADES;
4use crate::properties::{Error, PropertyResult, Reading};
5use crate::xml::{Access, AccessError, Name, Snapshot, Xml};
6use structured_asn1::memory::{OwnedVec, Work};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Kind {
11 Claimed,
13 AttributeCertificate,
15 OtherCertificate,
17 Assertion,
19}
20
21#[derive(Debug, Clone, Copy)]
23pub struct Entry<N> {
24 pub node: N,
26 pub group: N,
28 pub kind: Kind,
30}
31
32#[derive(Debug)]
34pub struct Roles<N, D, G> {
35 snapshot: Snapshot<D, G>,
36 signature: N,
37 node: N,
38 entries: OwnedVec<Entry<N>>,
39}
40
41impl<N: Copy, D: Copy, G: Copy> Roles<N, D, G> {
42 #[must_use]
44 pub fn snapshot(&self) -> Snapshot<D, G> {
45 self.snapshot
46 }
47 #[must_use]
49 pub fn signature(&self) -> N {
50 self.signature
51 }
52 #[must_use]
54 pub fn node(&self) -> N {
55 self.node
56 }
57 #[must_use]
59 pub fn entries(&self) -> &[Entry<N>] {
60 &self.entries
61 }
62}
63
64pub type Catalogue<X> = Roles<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
66
67pub fn read<X: Xml, W: Work>(
74 access: &Access<'_, X, W>,
75 signed: &Reading<X>,
76) -> PropertyResult<Option<Catalogue<X>>, X> {
77 if access.snapshot() != signed.snapshot() {
78 return Err(Error::Access(AccessError::Changed {
79 node: signed.parent(),
80 }));
81 }
82 access
84 .query(signed.parent(), |_, _, _| Ok(()))
85 .map_err(Error::Access)?;
86 let Some(node) = signed.role() else {
87 return Ok(None);
88 };
89 read_node(access, signed.snapshot(), signed.signature(), node).map(Some)
90}
91
92pub(crate) fn locate<X: Xml, W: Work>(
95 access: &Access<'_, X, W>,
96 layout: &crate::container::Layout<X>,
97) -> PropertyResult<Option<X::Id>, X> {
98 let (parent, _) = crate::properties::sections(access, layout)?;
99 let Some(parent) = parent else {
100 return Ok(None);
101 };
102 let mut selected = None;
103 for child in access.children(parent) {
104 let node = child.map_err(Error::Child)?;
105 if access
106 .has_name(
107 node,
108 Name {
109 namespace: XADES,
110 local: "SignerRoleV2",
111 },
112 )
113 .map_err(Error::Access)?
114 {
115 if selected.is_some() {
116 return Err(Error::Duplicate { node });
117 }
118 selected = Some(node);
119 }
120 }
121 Ok(selected)
122}
123
124pub(crate) fn read_node<X: Xml, W: Work>(
127 access: &Access<'_, X, W>,
128 snapshot: Snapshot<X::Document, X::Generation>,
129 signature: X::Id,
130 node: X::Id,
131) -> PropertyResult<Catalogue<X>, X> {
132 if snapshot != access.snapshot() {
133 return Err(Error::Access(AccessError::Changed { node }));
134 }
135 let mut entries = access
136 .query(node, |_, _, work| Ok(work.vector()))
137 .map_err(Error::Access)?;
138 let mut previous = None;
139 for child in access.children(node) {
140 let group = child.map_err(Error::Child)?;
141 let rank = rank(access, group)?;
142 if previous == Some(rank) {
143 return Err(Error::Duplicate { node: group });
144 }
145 if previous.is_some_and(|value| value > rank) {
146 return Err(Error::Order { node: group });
147 }
148 previous = Some(rank);
149 let mut populated = false;
150 for child in access.children(group) {
151 let child = child.map_err(Error::Child)?;
152 let (payload, kind) = match rank {
153 0 => {
154 expect(access, child, "ClaimedRole")?;
155 (child, Kind::Claimed)
156 }
157 1 => {
158 expect(access, child, "CertifiedRole")?;
159 credential(access, child)?
160 }
161 _ => {
162 expect(access, child, "SignedAssertion")?;
163 (child, Kind::Assertion)
164 }
165 };
166 entries
167 .try_push(Entry {
168 node: payload,
169 group,
170 kind,
171 })
172 .map_err(|cause| Error::Resource { node: child, cause })?;
173 populated = true;
174 }
175 if !populated {
176 return Err(Error::Missing {
177 parent: group,
178 local: "role value",
179 });
180 }
181 }
182 Ok(Roles {
183 snapshot,
184 signature,
185 node,
186 entries: entries.into_owned(),
187 })
188}
189
190fn rank<X: Xml, W: Work>(access: &Access<'_, X, W>, node: X::Id) -> PropertyResult<usize, X> {
191 for (rank, local) in ["ClaimedRoles", "CertifiedRolesV2", "SignedAssertions"]
192 .into_iter()
193 .enumerate()
194 {
195 if access
196 .has_name(
197 node,
198 Name {
199 namespace: XADES,
200 local,
201 },
202 )
203 .map_err(Error::Access)?
204 {
205 return Ok(rank);
206 }
207 }
208 Err(Error::Unexpected { node })
209}
210
211fn expect<X: Xml, W: Work>(
212 access: &Access<'_, X, W>,
213 node: X::Id,
214 local: &'static str,
215) -> PropertyResult<(), X> {
216 if !access
217 .has_name(
218 node,
219 Name {
220 namespace: XADES,
221 local,
222 },
223 )
224 .map_err(Error::Access)?
225 {
226 return Err(Error::Unexpected { node });
227 }
228 Ok(())
229}
230
231fn credential<X: Xml, W: Work>(
232 access: &Access<'_, X, W>,
233 node: X::Id,
234) -> PropertyResult<(X::Id, Kind), X> {
235 let mut children = access.children(node);
236 let value = children
237 .next()
238 .transpose()
239 .map_err(Error::Child)?
240 .ok_or(Error::Missing {
241 parent: node,
242 local: "attribute certificate",
243 })?;
244 let kind = if access
245 .has_name(
246 value,
247 Name {
248 namespace: XADES,
249 local: "X509AttributeCertificate",
250 },
251 )
252 .map_err(Error::Access)?
253 {
254 Kind::AttributeCertificate
255 } else {
256 expect(access, value, "OtherAttributeCertificate")?;
257 Kind::OtherCertificate
258 };
259 if let Some(extra) = children.next() {
260 return Err(Error::Unexpected {
261 node: extra.map_err(Error::Child)?,
262 });
263 }
264 Ok((value, kind))
265}