use crate::bindings;
use crate::XmlDocument;
use crate::XmlSecCanonicalizationMethod;
use crate::XmlSecSignatureMethod;
use crate::XmlSecError;
use crate::XmlSecResult;
use std::ffi::CString;
use std::os::raw::c_uchar;
use std::ptr::null;
pub trait TemplateBuilder
{
fn canonicalization(self, c14n: XmlSecCanonicalizationMethod) -> Self;
fn signature(self, sig: XmlSecSignatureMethod) -> Self;
fn reference_signature(self, sig: XmlSecSignatureMethod) -> Self;
fn uri(self, uri: &str) -> Self;
fn ns_prefix(self, ns_prefix: &str) -> Self;
fn keyname(self, add: bool) -> Self;
fn keyvalue(self, add: bool) -> Self;
fn x509data(self, add: bool) -> Self;
fn done(self) -> XmlSecResult<()>;
}
pub trait XmlDocumentTemplating<'d>
{
fn template(&'d self) -> XmlDocumentTemplateBuilder<'d>;
}
pub struct XmlDocumentTemplateBuilder<'d>
{
doc: &'d XmlDocument,
options: TemplateOptions,
}
struct TemplateOptions
{
c14n: XmlSecCanonicalizationMethod,
sig: XmlSecSignatureMethod,
refsig: XmlSecSignatureMethod,
ns_prefix: Option<String>,
uri: Option<String>,
keyname: bool,
keyvalue: bool,
x509data: bool,
}
impl Default for TemplateOptions
{
fn default() -> Self
{
Self {
c14n: XmlSecCanonicalizationMethod::ExclusiveC14N,
sig: XmlSecSignatureMethod::RsaSha1,
refsig: XmlSecSignatureMethod::Sha1,
uri: None,
ns_prefix: None,
keyname: false,
keyvalue: false,
x509data: false,
}
}
}
impl<'d> XmlDocumentTemplating<'d> for XmlDocument
{
fn template(&'d self) -> XmlDocumentTemplateBuilder<'d>
{
crate::xmlsec::guarantee_xmlsec_init();
XmlDocumentTemplateBuilder {doc: self, options: TemplateOptions::default()}
}
}
impl<'d> TemplateBuilder for XmlDocumentTemplateBuilder<'d>
{
fn canonicalization(mut self, c14n: XmlSecCanonicalizationMethod) -> Self
{
self.options.c14n = c14n;
self
}
fn signature(mut self, sig: XmlSecSignatureMethod) -> Self
{
self.options.sig = sig;
self
}
fn reference_signature(mut self, sig: XmlSecSignatureMethod) -> Self
{
self.options.refsig = sig;
self
}
fn uri(mut self, uri: &str) -> Self
{
self.options.uri = Some(uri.to_owned());
self
}
fn ns_prefix(mut self, ns_prefix: &str) -> Self
{
self.options.ns_prefix = Some(ns_prefix.to_owned());
self
}
fn keyname(mut self, add: bool) -> Self
{
self.options.keyname = add;
self
}
fn keyvalue(mut self, add: bool) -> Self
{
self.options.keyvalue = add;
self
}
fn x509data(mut self, add: bool) -> Self
{
self.options.x509data = add;
self
}
fn done(self) -> XmlSecResult<()>
{
let curi = {
if let Some(uri) = self.options.uri {
CString::new(uri).unwrap().into_raw() as *const c_uchar
} else {
null()
}
};
let c_ns_prefix = {
if let Some(ns_prefix) = self.options.ns_prefix {
CString::new(ns_prefix).unwrap().into_raw() as *const c_uchar
} else {
null()
}
};
let docptr = self.doc.doc_ptr() as *mut bindings::xmlDoc;
let rootptr = if let Some(root) = self.doc.get_root_element() {
root.node_ptr() as *mut bindings::xmlNode
} else {
return Err(XmlSecError::RootNotFound);
};
let signature = unsafe { bindings::xmlSecTmplSignatureCreateNsPref(
docptr,
self.options.c14n.to_method(),
self.options.sig.to_method(),
null(),
c_ns_prefix,
) };
if signature.is_null() {
panic!("Failed to create signature template");
}
let reference = unsafe { bindings::xmlSecTmplSignatureAddReference(
signature,
self.options.refsig.to_method(),
null(),
curi,
null(),
) };
if reference.is_null() {
panic!("Failed to add enveloped transform to reference");
}
let envelope = unsafe { bindings::xmlSecTmplReferenceAddTransform(reference, bindings::xmlSecTransformEnvelopedGetKlass()) };
if envelope.is_null() {
panic!("Failed to add enveloped transform")
}
let keyinfo = unsafe { bindings::xmlSecTmplSignatureEnsureKeyInfo(signature, null()) };
if keyinfo.is_null() {
panic!("Failed to ensure key info");
}
if self.options.keyname
{
let keyname = unsafe { bindings::xmlSecTmplKeyInfoAddKeyName(keyinfo, null()) };
if keyname.is_null() {
panic!("Failed to add key name");
}
}
if self.options.keyvalue
{
let keyvalue = unsafe { bindings::xmlSecTmplKeyInfoAddKeyValue(keyinfo) };
if keyvalue.is_null() {
panic!("Failed to add key value");
}
}
if self.options.x509data
{
let x509data = unsafe { bindings::xmlSecTmplKeyInfoAddX509Data(keyinfo) };
if x509data.is_null() {
panic!("Failed to add key value");
}
}
unsafe { bindings::xmlAddChild(rootptr, signature) };
Ok(())
}
}