# This file is part of CycloneDX Python Library # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # SPDX-License-Identifier: Apache-2.0 # Copyright (c) OWASP Foundation. All Rights Reserved. from typing import Any, Iterable, Optional, Union import py_serializable as serializable from sortedcontainers import SortedSet from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str from .._internal.compare import ComparableTuple as _ComparableTuple from ..schema.schema import SchemaVersion1Dot6 from . import XsUri from .bom_ref import BomRef @serializable.serializable_class class PostalAddress: """ This is our internal representation of the `postalAddressType` complex type that can be used in multiple places within a CycloneDX BOM document. .. note:: See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.6/xml/#type_postalAddressType """ def __init__( self, *, bom_ref: Optional[Union[str, BomRef]] = None, country: Optional[str] = None, region: Optional[str] = None, locality: Optional[str] = None, post_office_box_number: Optional[str] = None, postal_code: Optional[str] = None, street_address: Optional[str] = None, ) -> None: self._bom_ref = _bom_ref_from_str(bom_ref, optional=True) self.country = country self.region = region self.locality = locality self.post_office_box_number = post_office_box_number self.postal_code = postal_code self.street_address = street_address @property @serializable.json_name('bom-ref') @serializable.type_mapping(BomRef) @serializable.xml_attribute() @serializable.xml_name('bom-ref') def bom_ref(self) -> Optional[BomRef]: """ An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref MUST be unique within the BOM. Returns: `BomRef` """ return self._bom_ref @property @serializable.xml_sequence(10) def country(self) -> Optional[str]: """ The country name or the two-letter ISO 3166-1 country code. Returns: `str` or `None` """ return self._country @country.setter def country(self, country: Optional[str]) -> None: self._country = country @property @serializable.xml_sequence(20) def region(self) -> Optional[str]: """ The region or state in the country. For example, Texas. Returns: `str` or `None` """ return self._region @region.setter def region(self, region: Optional[str]) -> None: self._region = region @property @serializable.xml_sequence(30) def locality(self) -> Optional[str]: """ The locality or city within the country. For example, Austin. Returns: `str` or `None` """ return self._locality @locality.setter def locality(self, locality: Optional[str]) -> None: self._locality = locality @property @serializable.xml_sequence(40) def post_office_box_number(self) -> Optional[str]: """ The post office box number. For example, 901. Returns: `str` or `None` """ return self._post_office_box_number @post_office_box_number.setter def post_office_box_number(self, post_office_box_number: Optional[str]) -> None: self._post_office_box_number = post_office_box_number @property @serializable.xml_sequence(60) def postal_code(self) -> Optional[str]: """ The postal code. For example, 78758. Returns: `str` or `None` """ return self._postal_code @postal_code.setter def postal_code(self, postal_code: Optional[str]) -> None: self._postal_code = postal_code @property @serializable.xml_sequence(70) def street_address(self) -> Optional[str]: """ The street address. For example, 100 Main Street. Returns: `str` or `None` """ return self._street_address @street_address.setter def street_address(self, street_address: Optional[str]) -> None: self._street_address = street_address def __comparable_tuple(self) -> _ComparableTuple: return _ComparableTuple(( self.country, self.region, self.locality, self.postal_code, self.post_office_box_number, self.street_address, None if self.bom_ref is None else self.bom_ref.value, )) def __eq__(self, other: object) -> bool: if isinstance(other, PostalAddress): return self.__comparable_tuple() == other.__comparable_tuple() return False def __lt__(self, other: Any) -> bool: if isinstance(other, PostalAddress): return self.__comparable_tuple() < other.__comparable_tuple() return NotImplemented def __hash__(self) -> int: return hash(self.__comparable_tuple()) def __repr__(self) -> str: return f'' @serializable.serializable_class class OrganizationalContact: """ This is our internal representation of the `organizationalContact` complex type that can be used in multiple places within a CycloneDX BOM document. .. note:: See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.6/xml/#type_organizationalContact """ def __init__( self, *, name: Optional[str] = None, phone: Optional[str] = None, email: Optional[str] = None, ) -> None: self.name = name self.email = email self.phone = phone @property @serializable.xml_sequence(1) @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) def name(self) -> Optional[str]: """ Get the name of the contact. Returns: `str` if set else `None` """ return self._name @name.setter def name(self, name: Optional[str]) -> None: self._name = name @property @serializable.xml_sequence(2) @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) def email(self) -> Optional[str]: """ Get the email of the contact. Returns: `str` if set else `None` """ return self._email @email.setter def email(self, email: Optional[str]) -> None: self._email = email @property @serializable.xml_sequence(3) @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) def phone(self) -> Optional[str]: """ Get the phone of the contact. Returns: `str` if set else `None` """ return self._phone @phone.setter def phone(self, phone: Optional[str]) -> None: self._phone = phone def __comparable_tuple(self) -> _ComparableTuple: return _ComparableTuple(( self.name, self.email, self.phone )) def __eq__(self, other: object) -> bool: if isinstance(other, OrganizationalContact): return self.__comparable_tuple() == other.__comparable_tuple() return False def __lt__(self, other: Any) -> bool: if isinstance(other, OrganizationalContact): return self.__comparable_tuple() < other.__comparable_tuple() return NotImplemented def __hash__(self) -> int: return hash(self.__comparable_tuple()) def __repr__(self) -> str: return f'' @serializable.serializable_class class OrganizationalEntity: """ This is our internal representation of the `organizationalEntity` complex type that can be used in multiple places within a CycloneDX BOM document. .. note:: See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.6/xml/#type_organizationalEntity """ def __init__( self, *, name: Optional[str] = None, urls: Optional[Iterable[XsUri]] = None, contacts: Optional[Iterable[OrganizationalContact]] = None, address: Optional[PostalAddress] = None, ) -> None: self.name = name self.address = address self.urls = urls or [] # type:ignore[assignment] self.contacts = contacts or [] # type:ignore[assignment] @property @serializable.xml_sequence(10) @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) def name(self) -> Optional[str]: """ Get the name of the organization. Returns: `str` if set else `None` """ return self._name @name.setter def name(self, name: Optional[str]) -> None: self._name = name @property @serializable.view(SchemaVersion1Dot6) @serializable.xml_sequence(20) def address(self) -> Optional[PostalAddress]: """ The physical address (location) of the organization. Returns: `PostalAddress` or `None` """ return self._address @address.setter def address(self, address: Optional[PostalAddress]) -> None: self._address = address @property @serializable.json_name('url') @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'url') @serializable.xml_sequence(30) def urls(self) -> 'SortedSet[XsUri]': """ Get a list of URLs of the organization. Multiple URLs are allowed. Returns: Set of `XsUri` """ return self._urls @urls.setter def urls(self, urls: Iterable[XsUri]) -> None: self._urls = SortedSet(urls) @property @serializable.json_name('contact') @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'contact') @serializable.xml_sequence(40) def contacts(self) -> 'SortedSet[OrganizationalContact]': """ Get a list of contact person at the organization. Multiple contacts are allowed. Returns: Set of `OrganizationalContact` """ return self._contacts @contacts.setter def contacts(self, contacts: Iterable[OrganizationalContact]) -> None: self._contacts = SortedSet(contacts) def __comparable_tuple(self) -> _ComparableTuple: return _ComparableTuple(( self.name, _ComparableTuple(self.urls), _ComparableTuple(self.contacts) )) def __eq__(self, other: object) -> bool: if isinstance(other, OrganizationalEntity): return self.__comparable_tuple() == other.__comparable_tuple() return False def __lt__(self, other: Any) -> bool: if isinstance(other, OrganizationalEntity): return self.__comparable_tuple() < other.__comparable_tuple() return NotImplemented def __hash__(self) -> int: return hash(self.__comparable_tuple()) def __repr__(self) -> str: return f''