def process_model(self, template_root: et.ElementBase, diagram_root: et.ElementBase): """Обработка модели и создание выходной диаграммы с использованием шаблона""" print("MODEL:") # print(model) pprint(self.model, indent=2, width=120) figure_templates: Dict[str, et.ElementBase] = {} for obj in template_root.findall(f'object[@type]'): obj_type: str = obj.attrib.get("type") figure_templates[obj_type] = obj print('TEMPLATE OBJECTS:') pprint(list(figure_templates.keys())) # словарь условных стилей, применяемых к фигурам в зависимости от значений их атрибутов # ключ = ключ из модели # значение - массив из xml-объектов, в каждом из которых определены свойства key, value и style # - key: используется в качестве ключа. # Стиль будет применен к фигурам, для которых в yml-модели указан данный ключ # - value: используется как селектор значений. # Будет применен стиль объекта, для которого в yml-модели для ключа key указано данное значение # - attributes: используется как селектор атрибутов. Список имен атрибутов, разделенный символом ';' # К целевой фигуре будут применены атрибуты форматирования фигуры со стилем, перечисленные в style style_templates: Dict[str, List[et.ElementBase]] = {} for obj in template_root.findall(f'object[@key]'): style_key: str = obj.attrib.get("key") if style_key not in style_templates: style_templates[style_key] = [] style_templates[style_key].append(obj) print('STYLE OBJECTS:') pprint(list(style_templates.keys())) # шаблонов фигур # for obj in figure_templates.values(): # obj.getparent().remove(obj) # # for styles in style_templates.values(): # for obj in styles: # obj.getparent().remove(obj) # обработаем модель root_figure: Figure = Figure() model = Model(figure_templates, style_templates, diagram_root) model.iterate(self.model, root_figure) root_figure.resize() # очистим выходную диаграмму от объектов, которых нет в модели for obj in diagram_root.findall(f'object'): if obj.attrib['id'] not in g_figures: diagram_root.remove(obj)
def _get_default_value_from_section(self, section: etree.ElementBase): """ <Default> <item> 1.0 </item> <item> 1.0 </item> <item> 1.0 </item> </Default> """ defaults = [] for it in section.findall('item'): defaults.append(self.type.get_default_value(it)) return defaults
def rss_document_to_feed_items(feed: Feed, tree: ElementBase) -> List[FeedItem]: """Creates a list of FeedItem objects from a xml tree for the feed.""" item_elements = tree.findall("channel/item") return [ FeedItem( feed_id=feed.feed_id, title=item_element.findtext("title"), link=sanitize_link(item_element.findtext("link")), description=parse_description( item_element.findtext("description")), last_seen=now_in_utc(), published=_parse_optional_rss_datetime( item_element.findtext("pubDate")), created_on=now_in_utc(), ) for item_element in item_elements ]
def atom_document_to_feed_items(feed: Feed, tree: ElementBase) -> List[FeedItem]: item_elements = tree.findall("{http://www.w3.org/2005/Atom}entry") return [ FeedItem( feed_id=feed.feed_id, title=item_element.findtext("{http://www.w3.org/2005/Atom}title"), link=_parse_optional_link_for_href( item_element.find("{http://www.w3.org/2005/Atom}link")), description=item_element.findtext( "{http://www.w3.org/2005/Atom}content") or "", last_seen=now_in_utc(), published=_parse_optional_datetime( item_element.findtext( "{http://www.w3.org/2005/Atom}published")), created_on=now_in_utc(), ) for item_element in item_elements ]
def from_section(cls, section: etree.ElementBase, alias): args = [] if section.find('Args') is not None: for item in section.find('Args'): args.append( MethodArgument( name=item.tag, type_=alias.get_data_type_from_section(item))) else: for item in section.findall('Arg'): args.append( MethodArgument( type_=alias.get_data_type_from_section(item))) header_section = section.find('VariableLengthHeaderSize') try: header_size = int(header_section.text.strip()) except (ValueError, AttributeError): header_size = DEFAULT_HEADER_SIZE return cls(section.tag, list(args), header_size)
def verify_xml_signature( xml_doc: XmlElement, trusted_x509_cert: Union[crypto_utils.X509Cert, crypto_utils._X509CertOpenSsl] = None, ) -> Tuple[bytes, XmlElementTree, XmlElementTree]: """ Verify the XML signature in ``xml_doc``. .. note:: XML document with more than one signature is not supported. If the inputs are ok but the XML signature does not verify, raises :class:`XmlSignatureUnverified`. If ``trusted_x509_cert`` is None, it requires that the signature in ``xml_doc`` includes a a valid X.509 **certificate chain** that validates against the *known certificate authorities*. If ``trusted_x509_cert`` is given, it must be a **trusted** external X.509 certificate, and the verification will be of whether the XML signature in ``xml_doc`` was signed by ``trusted_x509_cert`` or not; thus **it overrides** any X.509 certificate information included in the signature. .. note:: It is strongly recommended to validate ``xml_doc`` beforehand (against the corresponding XML schema, using :func:`validate_xml_doc`). :param xml_doc: :param trusted_x509_cert: a trusted external X.509 certificate, or None :raises :class:`XmlSignatureUnverified`: signature did not verify :raises :class:`XmlSignatureInvalidCertificate`: certificate validation failed :raises :class:`XmlSignatureInvalid`: signature is invalid :raises :class:`XmlSchemaDocValidationError`: XML doc is not valid :raises :class:`ValueError`: """ if not isinstance(xml_doc, XmlElement): raise TypeError("'xml_doc' must be an XML document/element.") n_signatures = ( len(xml_doc.findall('.//ds:Signature', namespaces=XML_DSIG_NS_MAP)) + len(xml_doc.findall('.//dsig11:Signature', namespaces=XML_DSIG_NS_MAP)) + len(xml_doc.findall('.//dsig2:Signature', namespaces=XML_DSIG_NS_MAP))) if n_signatures > 1: raise NotImplementedError( "XML document with more than one signature is not supported.") xml_verifier = signxml.XMLVerifier() if isinstance(trusted_x509_cert, crypto_utils._X509CertOpenSsl): trusted_x509_cert_open_ssl = trusted_x509_cert elif isinstance(trusted_x509_cert, crypto_utils.X509Cert): trusted_x509_cert_open_ssl = crypto_utils._X509CertOpenSsl.from_cryptography( trusted_x509_cert) elif trusted_x509_cert is None: trusted_x509_cert_open_ssl = None else: # A 'crypto_utils._X509CertOpenSsl' is ok but we prefer 'crypto_utils.X509Cert'. raise TypeError( "'trusted_x509_cert' must be a 'crypto_utils.X509Cert' instance, or None." ) # warning: performance issue. # note: 'signxml.XMLVerifier.verify()' calls 'signxml.util.XMLProcessor.get_root()', # which converts the data to string, and then reparses it using the same function we use # in 'parse_untrusted_xml()' ('defusedxml.lxml.fromstring'), but without all the precautions # we have there. See: # https://github.com/XML-Security/signxml/blob/v2.6.0/signxml/util/__init__.py#L141-L151 # Considering that, we'd rather write to bytes ourselves and control the process. f = io.BytesIO() write_xml_doc(xml_doc, f) tmp_bytes = f.getvalue() try: # note: by passing 'x509_cert' we override any X.509 certificate information supplied # by the signature itself. # note: when an X509Data element is present in the signature and used for verification, but # a KeyValue element is also present, there is an ambiguity and a security hazard because # the public key used to sign the document is already encoded in the certificate (which is # in X509Data), so the verifier must either ignore KeyValue or ensure that it matches what # is in the certificate. SignXML does not perform that validation and throws an # 'InvalidInput' error instead. # # SII's schema for XML signatures requires both elements to be present, which forces us to # enable 'ignore_ambiguous_key_info' to bypass the error and validate the signature using # X509Data only. # # Source: # https://github.com/XML-Security/signxml/commit/ef15da8dbb904f1dedfdd210ae3e0df5da535612 result: signxml.VerifyResult = xml_verifier.verify( data=tmp_bytes, require_x509=True, x509_cert=trusted_x509_cert_open_ssl, ignore_ambiguous_key_info=True, ) except signxml.exceptions.InvalidDigest as exc: # warning: catch before 'InvalidSignature' (it is the parent of 'InvalidDigest'). raise XmlSignatureUnverified(str(exc)) from exc except signxml.exceptions.InvalidCertificate as exc: # warning: catch before 'InvalidSignature' (it is the parent of 'InvalidCertificate'). raise XmlSignatureInvalidCertificate(str(exc)) from exc except signxml.exceptions.InvalidSignature as exc: # XML signature is invalid, for any reason. raise XmlSignatureInvalid(str(exc)) from exc except signxml.exceptions.InvalidInput as exc: raise ValueError("Invalid input.", str(exc)) from exc except lxml.etree.DocumentInvalid as exc: # Simplest and safest way to get the error message (see 'validate_xml_doc()'). # Error example: # "Element '{http://www.w3.org/2000/09/xmldsig#}X509Certificate': '\nabc\n' is not a # valid value of the atomic type 'xs:base64Binary'., line 30" validation_error_msg = str(exc) raise XmlSchemaDocValidationError(validation_error_msg) from exc return result.signed_data, result.signed_xml, result.signature_xml