def flatten_xml(xml: etree._Element): pages = xml.xpath('/pdf2xml/page') children = [] for page in pages: for child in page: children.append(child) xml.remove(page) for child in children: xml.append(child)
def sign( *, element: Element, private_key: RSAPrivateKey, certificate: Certificate, config: SigningConfig = SigningConfig.default(), index: int = 0, ) -> bytes: try: element_id = element.attrib["ID"] except KeyError: raise NoIDAttribute(element) # Generate the digest value of the element/content to be signed content_digest_value = utils.ascii_b64( utils.hash_digest(config.digest_method, utils.serialize_xml(element))) # Build the SignedInfo tag, referencing the element we got passed, # including the digest value we just created. signed_info = ds.SignedInfo( ds.CanonicalizationMethod(Algorithm=XML_EXC_C14N), ds.SignatureMethod(Algorithm=utils.signature_method_algorithm( config.signature_method)), ds.Reference( ds.Transforms( ds.Transform(Algorithm=XMLDSIG_ENVELOPED_SIGNATURE), ds.Transform(Algorithm=XML_EXC_C14N), ), ds.DigestMethod( Algorithm=utils.digest_method_algorithm(config.digest_method)), ds.DigestValue(content_digest_value), # Embed the digest value URI="#" + element_id, # Reference the element to sign ), ) # Sign the digest of the SignedInfo element signature = utils.sign(utils.serialize_xml(signed_info), private_key, config.signature_method) signature_value = utils.ascii_b64(signature) # Encode the certificate to embed into the signature. cert_data = utils.ascii_b64(certificate.public_bytes(Encoding.DER)) signature_element = ds.Signature( signed_info, ds.SignatureValue(signature_value), ds.KeyInfo(ds.X509Data(ds.X509Certificate(cert_data))), ) element.insert(index, signature_element) root = utils.get_root(element) result = utils.serialize_xml(root) element.remove(signature_element) return result
def _set_nvpair(nvset_element: _Element, id_provider: IdProvider, name: str, value: str) -> None: """ Ensure name-value pair is set / removed in specified nvset nvset_element -- container for nvpair elements to update id_provider -- elements' ids generator name -- name of the nvpair to be set value -- value of the nvpair to be set, if "" the nvpair will be removed """ nvpair_el_list = cast( # The xpath method has a complicated return value, but we know our xpath # expression returns only elements. List[_Element], nvset_element.xpath("./nvpair[@name=$name]", name=name), ) if not nvpair_el_list: if value != "": etree.SubElement( nvset_element, "nvpair", { "id": create_subelement_id( nvset_element, # limit id length to prevent excessively long ids name[:20], id_provider, ), "name": name, "value": value, }, ) return if value != "": nvpair_el_list[0].attrib["value"] = value else: nvset_element.remove(nvpair_el_list[0]) for nvpair_el in nvpair_el_list[1:]: nvset_element.remove(nvpair_el)