use crate::container::DS;
use crate::properties::{self, Error, PropertyResult};
use crate::timestamp::XADES_141;
use crate::unsigned;
use crate::xml::{Access, AccessError, Name, Snapshot, Xml};
use structured_asn1::memory::{OwnedVec, Work};
mod check;
mod create;
pub use check::{
CheckError, CheckResult, Checked, PairCheck, PairOutcome, Report, SourceError, State, check,
};
pub use create::{
Candidate, Created, CreationError, CreationResult, MethodProvider, Renewal, create,
};
mod prepared;
pub use prepared::{PreparedChecks, PreparedResult, check_prepared};
#[derive(Debug, Clone, Copy)]
pub struct Pair<N> {
pub node: N,
pub object: N,
pub reference: N,
}
#[derive(Debug)]
pub struct Catalogue<N, D, G> {
snapshot: Snapshot<D, G>,
signature: N,
node: N,
canonicalization: N,
digest: N,
pairs: OwnedVec<Pair<N>>,
}
impl<N: Copy, D: Copy, G: Copy> Catalogue<N, D, G> {
#[must_use]
pub fn snapshot(&self) -> Snapshot<D, G> {
self.snapshot
}
#[must_use]
pub fn signature(&self) -> N {
self.signature
}
#[must_use]
pub fn node(&self) -> N {
self.node
}
#[must_use]
pub fn canonicalization(&self) -> N {
self.canonicalization
}
#[must_use]
pub fn digest(&self) -> N {
self.digest
}
#[must_use]
pub fn pairs(&self) -> &[Pair<N>] {
&self.pairs
}
}
pub type Reading<X> = Catalogue<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
pub fn read<X: Xml, W: Work>(
access: &Access<'_, X, W>,
inventory: &unsigned::Reading<X>,
index: usize,
) -> PropertyResult<Reading<X>, X> {
if access.snapshot() != inventory.snapshot() {
return Err(Error::Access(AccessError::Changed {
node: inventory.signature(),
}));
}
access
.query(inventory.signature(), |_, _, work| Ok(work.charge_work(1)))
.map_err(Error::Access)?
.map_err(|cause| Error::Resource {
node: inventory.signature(),
cause,
})?;
let entry = inventory.entries().get(index).ok_or(Error::Selection {
parent: inventory.signature(),
index,
})?;
if entry.role != unsigned::Role::RenewedDigests {
return Err(Error::Unexpected { node: entry.node });
}
let node = entry.node;
let mut children = access.children(node);
let canonicalization =
children
.next()
.transpose()
.map_err(Error::Child)?
.ok_or(Error::Missing {
parent: node,
local: "CanonicalizationMethod",
})?;
named(access, canonicalization, DS, "CanonicalizationMethod")?;
let digest = children
.next()
.transpose()
.map_err(Error::Child)?
.ok_or(Error::Missing {
parent: node,
local: "DigestMethod",
})?;
named(access, digest, DS, "DigestMethod")?;
let mut pairs = access
.query(node, |_, _, work| Ok(work.vector()))
.map_err(Error::Access)?;
for child in children {
let child = child.map_err(Error::Child)?;
named(access, child, XADES_141, "RecomputedDigestValue")?;
let mut fields = access.children(child);
let object = fields
.next()
.transpose()
.map_err(Error::Child)?
.ok_or(Error::Missing {
parent: child,
local: "NewSDODigestValue",
})?;
named(access, object, XADES_141, "NewSDODigestValue")?;
properties::simple_content(access, object)?;
let reference = fields
.next()
.transpose()
.map_err(Error::Child)?
.ok_or(Error::Missing {
parent: child,
local: "OriginalRefDigest",
})?;
named(access, reference, XADES_141, "OriginalRefDigest")?;
properties::simple_content(access, reference)?;
if let Some(extra) = fields.next() {
return Err(Error::Unexpected {
node: extra.map_err(Error::Child)?,
});
}
pairs
.try_push(Pair {
node: child,
object,
reference,
})
.map_err(|cause| Error::Resource { node: child, cause })?;
}
if pairs.is_empty() {
return Err(Error::Missing {
parent: node,
local: "RecomputedDigestValue",
});
}
Ok(Catalogue {
snapshot: inventory.snapshot(),
signature: inventory.signature(),
node,
canonicalization,
digest,
pairs: pairs.into_owned(),
})
}
fn named<X: Xml, W: Work>(
access: &Access<'_, X, W>,
node: X::Id,
namespace: &str,
local: &str,
) -> PropertyResult<(), X> {
if !access
.has_name(node, Name { namespace, local })
.map_err(Error::Access)?
{
return Err(Error::Unexpected { node });
}
Ok(())
}