use super::{Error, Source, Types};
use crate::{
content::Content,
error::{Error as ArchiveError, resource},
uri::{self, Part},
zip::{Archive, Member, MemberId, ReadFailure},
};
use core::future::Future;
use structured_asn1::{
memory::{MemoryError, OwnedVec, Work},
range::RangeSource,
};
use structured_xades::{
attributes::AttributeXml,
binary::OwnedBinaryXml,
binding::{Coverage, Status},
reference::{Completeness, Descriptor, Parent, ReferenceXml, VisitError},
scalar::{ScalarXml, UriXml},
xml::{Access, AccessError, Snapshot, Xml},
};
pub struct Resource<'v, 's, S: RangeSource> {
member: Member<'v, 's, S>,
}
impl<S: RangeSource> Resource<'_, '_, S> {
#[must_use]
pub fn member(&self) -> MemberId<S::Document, S::Generation> {
self.member.id()
}
}
pub struct Loaded<'v, 's, S: RangeSource> {
content: Content<'v, 's, S>,
}
impl<'v, 's, S: RangeSource> Loaded<'v, 's, S> {
pub fn into_parts(self) -> (OwnedVec<u8>, Resource<'v, 's, S>) {
let (member, bytes) = self.content.into_parts();
(bytes, Resource { member })
}
}
pub enum Lookup<'v, 's, S: RangeSource> {
Loaded(Loaded<'v, 's, S>),
SameDocument(Part),
Part(Part),
Root,
Missing,
Ambiguous,
Negative(uri::Negative),
}
pub struct Resources<'v, 's, S: RangeSource> {
archive: &'v Archive<'s, S>,
base: MemberId<S::Document, S::Generation>,
}
impl<'v, 's, S: RangeSource> Resources<'v, 's, S> {
#[must_use]
pub fn base(&self) -> MemberId<S::Document, S::Generation> {
self.base
}
pub async fn load<W: Work>(
&self,
base: MemberId<S::Document, S::Generation>,
uri: &str,
work: &W,
) -> Result<Lookup<'v, 's, S>, ReadFailure<S::Error, S::Document, S::Generation>> {
let execution = self.archive.session().query(work);
let fail = |cause| ReadFailure::Processing {
member: base,
cause,
};
let base = self.archive.original(base, &execution).map_err(fail)?;
let target = uri::resolve(base.name(), uri, &execution)
.map_err(|cause| fail(resource(base.central_span(), cause)))?;
let names = match target {
uri::Target::Negative(cause) => return Ok(Lookup::Negative(cause)),
uri::Target::SameDocument(part) => return Ok(Lookup::SameDocument(part)),
uri::Target::Root(_) => return Ok(Lookup::Root),
uri::Target::Member {
name,
part: Part::Whole,
} => self.archive.find(name.as_ref(), &execution).map_err(fail)?,
uri::Target::Member { part, .. } => return Ok(Lookup::Part(part)),
};
if names.is_empty() {
return Ok(Lookup::Missing);
}
if names.len() != 1 {
return Ok(Lookup::Ambiguous);
}
let member = names
.member(0, &execution)
.map_err(fail)?
.expect("one exact original candidate");
let content = member.content(&execution).await?;
Ok(Lookup::Loaded(Loaded { content }))
}
}
pub struct MemberReference<'a, 'v, 's, N, S: RangeSource> {
pub descriptor: Descriptor<'a, N>,
pub resource: Option<&'a Resource<'v, 's, S>>,
}
pub trait MemberReferences<'v, 's, S: RangeSource>: ReferenceXml {
fn visit_member_references<VE, W: Work>(
&self,
snapshot: Snapshot<Self::Document, Self::Generation>,
signature: Self::Id,
work: &W,
visitor: impl for<'a> FnMut(MemberReference<'a, 'v, 's, Self::Id, S>) -> Result<(), VE>,
) -> Result<Completeness<Self::Id>, VisitError<Self::Error, VE>>;
}
pub trait SignatureParsed<'v, 's, S: RangeSource>: Types {
type View<'a>: Xml<
Id = Self::Id,
Document = Self::Document,
Generation = Self::Generation,
Error = Self::Error,
> + ScalarXml
+ AttributeXml
+ UriXml
+ OwnedBinaryXml
+ MemberReferences<'v, 's, S>
where
Self: 'a;
fn view(&self) -> Self::View<'_>;
fn root(&self) -> Self::Id;
}
pub trait SignatureFactory<'v, 's, S: RangeSource>: Types {
type Parsed<'a, W: Work + 'a>: SignatureParsed<
'v,
's,
S,
Id = Self::Id,
Document = Self::Document,
Generation = Self::Generation,
Error = Self::Error,
>
where
Self: 'a,
'v: 'a,
's: 'a,
's: 'v,
S: 's + 'v + 'a;
fn parse_signed<'a, W: Work + 'a>(
&'a self,
input: OwnedVec<u8>,
resources: &'a Resources<'v, 's, S>,
work: &'a W,
) -> impl Future<Output = Result<Self::Parsed<'a, W>, Self::Error>> + 'a
where
'v: 'a,
's: 'a,
's: 'v,
S: 's + 'v + 'a;
}
pub trait SignatureVisitor<'v, 's, F: Types + ?Sized, S: RangeSource> {
type Output;
type Error;
fn visit<X, W: Work>(
self,
source: Source<'_, 'v, 's, X, S, W>,
) -> impl Future<Output = Result<Self::Output, Self::Error>>
where
X: Xml<Id = F::Id, Document = F::Document, Generation = F::Generation, Error = F::Error>
+ ScalarXml
+ AttributeXml
+ UriXml
+ OwnedBinaryXml
+ MemberReferences<'v, 's, S>;
}
impl<'v, 's, S: RangeSource> Content<'v, 's, S> {
pub async fn with_signed_xml<
F: SignatureFactory<'v, 's, S>,
V: SignatureVisitor<'v, 's, F, S>,
W: Work,
>(
self,
factory: &F,
visitor: V,
work: &W,
) -> Result<
V::Output,
Error<
ReadFailure<S::Error, S::Document, S::Generation>,
F::Error,
V::Error,
AccessError<F::Error, F::Id>,
>,
> {
let archive = self.member().archive();
let execution = archive.session().query(work);
let (member, input) = self.into_parts();
let failure = |cause| {
Error::Input(ReadFailure::Processing {
member: member.id(),
cause,
})
};
archive
.admit(&execution, member.central_span())
.map_err(failure)?;
let resources = Resources {
archive,
base: member.id(),
};
let document = factory
.parse_signed(input, &resources, &execution)
.await
.map_err(Error::Produce)?;
let root = document.root();
let xml = document.view();
let snapshot = xml.snapshot();
let access = Access::new(&xml, snapshot, &execution);
access.inspect(root, |_| ()).map_err(Error::Xml)?;
archive
.admit(&execution, member.central_span())
.map_err(failure)?;
let result = visitor
.visit(Source {
member: &member,
xml: &xml,
root,
snapshot,
execution: &execution,
})
.await
.map_err(Error::Visit)?;
access.inspect(root, |_| ()).map_err(Error::Xml)?;
archive
.admit(&execution, member.central_span())
.map_err(failure)?;
Ok(result)
}
}
impl<'v, 's, S: RangeSource> Member<'v, 's, S> {
pub async fn with_signed_xml<
F: SignatureFactory<'v, 's, S>,
V: SignatureVisitor<'v, 's, F, S>,
W: Work,
>(
&self,
factory: &F,
visitor: V,
work: &W,
) -> Result<
V::Output,
Error<
ReadFailure<S::Error, S::Document, S::Generation>,
F::Error,
V::Error,
AccessError<F::Error, F::Id>,
>,
> {
self.content(work)
.await
.map_err(Error::Input)?
.with_signed_xml(factory, visitor, work)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Reference<N, D, G> {
pub node: N,
pub parent: Parent<N>,
pub input: Option<MemberId<D, G>>,
pub status: Status,
pub coverage: Coverage,
pub object_location: structured_xades::reference::ObjectLocation,
}
pub struct Signature<N, D, G> {
pub occurrence: crate::xml::Signature<N>,
pub status: Status,
pub completeness: Completeness<N>,
pub references: OwnedVec<Reference<N, D, G>>,
}
pub struct Facts<'v, 's, N, D, G, S: RangeSource> {
member: Member<'v, 's, S>,
reading: crate::xml::Reading<N, D, G>,
signatures: OwnedVec<Signature<N, S::Document, S::Generation>>,
}
pub struct Assessment<'a, A, N, D, G, SD, SG> {
member: MemberId<SD, SG>,
snapshot: Snapshot<D, G>,
signature: N,
inner: structured_xades::baseline::Assessment<'a, A, N, D, G>,
}
impl<A, N: Copy, D: Copy, G: Copy, SD: Copy, SG: Copy> Assessment<'_, A, N, D, G, SD, SG> {
#[must_use]
pub fn member(&self) -> MemberId<SD, SG> {
self.member
}
#[must_use]
pub fn signature(&self) -> N {
self.signature
}
#[must_use]
pub fn xades(&self) -> &structured_xades::baseline::Assessment<'_, A, N, D, G> {
&self.inner
}
}
#[derive(Debug)]
pub enum LevelError<E, N, SE> {
Xml(AccessError<E, N>),
Foreign,
Archive(ArchiveError<SE>),
Xades(structured_xades::baseline::LevelError),
}
pub type AssessmentResult<'a, A, X, S> = Result<
Assessment<
'a,
A,
<X as Xml>::Id,
<X as Xml>::Document,
<X as Xml>::Generation,
<S as RangeSource>::Document,
<S as RangeSource>::Generation,
>,
LevelError<<X as Xml>::Error, <X as Xml>::Id, <S as RangeSource>::Error>,
>;
pub type LevelAnswer<'r, 'a, A, N, D, G, SD, SG> = Option<&'r Assessment<'a, A, N, D, G, SD, SG>>;
pub type InspectionResult<'v, 's, X, S> = Result<
Facts<'v, 's, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation, S>,
InspectError<<X as Xml>::Error, <X as Xml>::Id, <S as RangeSource>::Error>,
>;
pub type MemberAssessment<'a, A, N, D, G, S> =
Assessment<'a, A, N, D, G, <S as RangeSource>::Document, <S as RangeSource>::Generation>;
pub type LevelsResult<'r, 'a, A, N, D, G, S> = Result<
Levels<'r, 'a, A, N, D, G, <S as RangeSource>::Document, <S as RangeSource>::Generation>,
JoinError<<S as RangeSource>::Error>,
>;
impl<'v, 's, X, S, W> Source<'_, 'v, 's, X, S, W>
where
X: MemberReferences<'v, 's, S>,
S: RangeSource,
W: Work,
{
pub fn assess<'a, A>(
&self,
evidence: structured_xades::baseline::Evidence<'a, A, X::Id, X::Document, X::Generation>,
) -> AssessmentResult<'a, A, X, S> {
use structured_xades::baseline::Evidence;
let prepared = match &evidence {
Evidence::Basic(value) => value.inputs().fields.prepared(),
Evidence::Timestamped(value) => value.basic().inputs().fields.prepared(),
Evidence::LongTerm(value)
| Evidence::Archival {
long_term: value, ..
} => value.timed().basic().inputs().fields.prepared(),
};
let containers = prepared.bound().containers();
if containers.snapshot() != self.snapshot {
return Err(LevelError::Foreign);
}
let signature = containers.signature();
let access = Access::new(self.xml, self.snapshot, self.execution);
if !access
.has_name(
signature,
structured_xades::xml::Name {
namespace: crate::manifest::DS,
local: "Signature",
},
)
.map_err(LevelError::Xml)?
{
return Err(LevelError::Foreign);
}
self.member
.archive()
.admit(self.execution, self.member.central_span())
.map_err(LevelError::Archive)?;
let inner = structured_xades::baseline::assess(evidence).map_err(LevelError::Xades)?;
Ok(Assessment {
member: self.member.id(),
snapshot: self.snapshot,
signature,
inner,
})
}
}
pub struct Levels<'r, 'a, A, N, D, G, SD, SG> {
answers: OwnedVec<LevelAnswer<'r, 'a, A, N, D, G, SD, SG>>,
all_roots: bool,
}
impl<'r, 'a, A, N, D, G, SD, SG> Levels<'r, 'a, A, N, D, G, SD, SG> {
#[must_use]
pub fn answers(&self) -> &[LevelAnswer<'r, 'a, A, N, D, G, SD, SG>] {
&self.answers
}
#[must_use]
pub fn all_roots_requested_level_met(&self) -> bool {
self.all_roots
}
}
#[derive(Debug)]
pub enum JoinError<E> {
Archive(ArchiveError<E>),
Foreign,
Duplicate,
}
impl<N: Copy + Eq + structured_asn1::memory::HashWork, D: Copy + Eq, G: Copy + Eq, S: RangeSource>
Facts<'_, '_, N, D, G, S>
{
pub fn levels<'r, 'a, A, W: Work>(
&self,
supplied: &[&'r MemberAssessment<'a, A, N, D, G, S>],
work: &W,
) -> LevelsResult<'r, 'a, A, N, D, G, S> {
let archive = self.member.archive();
let execution = archive.session().query(work);
archive
.admit(&execution, self.member.central_span())
.map_err(JoinError::Archive)?;
let refusal = |cause| JoinError::Archive(resource(self.member.central_span(), cause));
let mut originals = execution.map();
for (index, signature) in self.signatures.iter().enumerate() {
originals
.try_insert(signature.occurrence.node, index)
.map_err(refusal)?;
}
let mut selected = execution.map();
for (index, value) in supplied.iter().enumerate() {
execution.charge_work(1).map_err(refusal)?;
if value.member != self.member.id()
|| value.snapshot != self.reading.snapshot()
|| originals
.get(&value.signature, &execution)
.map_err(refusal)?
.is_none()
{
return Err(JoinError::Foreign);
}
if selected
.try_insert(value.signature, index)
.map_err(refusal)?
.is_some()
{
return Err(JoinError::Duplicate);
}
}
let mut answers = execution.vector();
answers
.try_reserve_exact(self.signatures.len())
.map_err(refusal)?;
let mut roots = 0usize;
let mut all_roots = true;
for signature in &self.signatures {
let answer = selected
.get(&signature.occurrence.node, &execution)
.map_err(refusal)?
.map(|index| supplied[*index]);
if signature.occurrence.direct {
roots += 1;
match answer {
Some(value) if value.inner.all_requirements_met() => {}
_ => all_roots = false,
}
}
answers.try_push(answer).map_err(refusal)?;
}
archive
.admit(&execution, self.member.central_span())
.map_err(JoinError::Archive)?;
Ok(Levels {
answers: answers.into_owned(),
all_roots: roots != 0 && all_roots,
})
}
}
impl<'v, 's, N: Copy, D: Copy, G: Copy, S: RangeSource> Facts<'v, 's, N, D, G, S> {
#[must_use]
pub fn member(&self) -> &Member<'v, 's, S> {
&self.member
}
#[must_use]
pub fn reading(&self) -> &crate::xml::Reading<N, D, G> {
&self.reading
}
#[must_use]
pub fn signatures(&self) -> &[Signature<N, S::Document, S::Generation>] {
&self.signatures
}
}
#[derive(Debug)]
pub enum InspectError<E, N, SE> {
Wrapper(crate::xml::Error<E, N>),
Xml(AccessError<E, N>),
References(VisitError<E, ReferenceError<SE>>),
Archive(ArchiveError<SE>),
}
#[derive(Debug)]
pub enum ReferenceError<E> {
Archive(ArchiveError<E>),
Foreign,
Resource(MemoryError),
}
impl<'v, 's, X, S, W> Source<'_, 'v, 's, X, S, W>
where
X: AttributeXml + MemberReferences<'v, 's, S>,
S: RangeSource,
W: Work,
{
pub fn signatures(&self) -> InspectionResult<'v, 's, X, S> {
let access = Access::new(self.xml, self.snapshot, self.execution);
let reading = crate::xml::inspect(self.xml, self.root, self.execution)
.map_err(InspectError::Wrapper)?;
let mut signatures = self.execution.vector();
for occurrence in reading.signatures() {
access
.inspect(occurrence.node, |_| ())
.map_err(InspectError::Xml)?;
let status = self
.xml
.signature_status(self.snapshot, occurrence.node, self.execution)
.map_err(|cause| InspectError::Xml(AccessError::Xml(cause)))?;
let mut references = self.execution.vector();
let completeness = self
.xml
.visit_member_references(self.snapshot, occurrence.node, self.execution, |item| {
let input = if let Some(resource) = item.resource {
self.execution
.charge_work(1)
.map_err(ReferenceError::Resource)?;
if !core::ptr::eq(resource.member.archive(), self.member.archive()) {
return Err(ReferenceError::Foreign);
}
self.member
.archive()
.original(resource.member(), self.execution)
.map_err(ReferenceError::Archive)?;
Some(resource.member())
} else {
None
};
references
.try_push(Reference {
node: item.descriptor.reference.node,
parent: item.descriptor.parent,
input,
status: item.descriptor.reference.status,
coverage: item.descriptor.reference.coverage,
object_location: item.descriptor.object_location,
})
.map_err(ReferenceError::Resource)
})
.map_err(InspectError::References)?;
access
.inspect(occurrence.node, |_| ())
.map_err(InspectError::Xml)?;
signatures
.try_push(Signature {
occurrence: *occurrence,
status,
completeness,
references: references.into_owned(),
})
.map_err(|cause| {
InspectError::Wrapper(crate::xml::Error::Resource {
node: occurrence.node,
cause,
})
})?;
}
let member = self
.member
.archive()
.original(self.member.id(), self.execution)
.map_err(InspectError::Archive)?;
access
.inspect(self.root, |_| ())
.map_err(InspectError::Xml)?;
Ok(Facts {
member,
reading,
signatures: signatures.into_owned(),
})
}
}