| | |
| | |
| | |
| |
|
| | from __future__ import annotations |
| |
|
| | import abc |
| | import ipaddress |
| | import typing |
| | from email.utils import parseaddr |
| |
|
| | from cryptography.x509.name import Name |
| | from cryptography.x509.oid import ObjectIdentifier |
| |
|
| | _IPAddressTypes = typing.Union[ |
| | ipaddress.IPv4Address, |
| | ipaddress.IPv6Address, |
| | ipaddress.IPv4Network, |
| | ipaddress.IPv6Network, |
| | ] |
| |
|
| |
|
| | class UnsupportedGeneralNameType(Exception): |
| | pass |
| |
|
| |
|
| | class GeneralName(metaclass=abc.ABCMeta): |
| | @property |
| | @abc.abstractmethod |
| | def value(self) -> typing.Any: |
| | """ |
| | Return the value of the object |
| | """ |
| |
|
| |
|
| | class RFC822Name(GeneralName): |
| | def __init__(self, value: str) -> None: |
| | if isinstance(value, str): |
| | try: |
| | value.encode("ascii") |
| | except UnicodeEncodeError: |
| | raise ValueError( |
| | "RFC822Name values should be passed as an A-label string. " |
| | "This means unicode characters should be encoded via " |
| | "a library like idna." |
| | ) |
| | else: |
| | raise TypeError("value must be string") |
| |
|
| | name, address = parseaddr(value) |
| | if name or not address: |
| | |
| | |
| | raise ValueError("Invalid rfc822name value") |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> str: |
| | return self._value |
| |
|
| | @classmethod |
| | def _init_without_validation(cls, value: str) -> RFC822Name: |
| | instance = cls.__new__(cls) |
| | instance._value = value |
| | return instance |
| |
|
| | def __repr__(self) -> str: |
| | return f"<RFC822Name(value={self.value!r})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, RFC822Name): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class DNSName(GeneralName): |
| | def __init__(self, value: str) -> None: |
| | if isinstance(value, str): |
| | try: |
| | value.encode("ascii") |
| | except UnicodeEncodeError: |
| | raise ValueError( |
| | "DNSName values should be passed as an A-label string. " |
| | "This means unicode characters should be encoded via " |
| | "a library like idna." |
| | ) |
| | else: |
| | raise TypeError("value must be string") |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> str: |
| | return self._value |
| |
|
| | @classmethod |
| | def _init_without_validation(cls, value: str) -> DNSName: |
| | instance = cls.__new__(cls) |
| | instance._value = value |
| | return instance |
| |
|
| | def __repr__(self) -> str: |
| | return f"<DNSName(value={self.value!r})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, DNSName): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class UniformResourceIdentifier(GeneralName): |
| | def __init__(self, value: str) -> None: |
| | if isinstance(value, str): |
| | try: |
| | value.encode("ascii") |
| | except UnicodeEncodeError: |
| | raise ValueError( |
| | "URI values should be passed as an A-label string. " |
| | "This means unicode characters should be encoded via " |
| | "a library like idna." |
| | ) |
| | else: |
| | raise TypeError("value must be string") |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> str: |
| | return self._value |
| |
|
| | @classmethod |
| | def _init_without_validation(cls, value: str) -> UniformResourceIdentifier: |
| | instance = cls.__new__(cls) |
| | instance._value = value |
| | return instance |
| |
|
| | def __repr__(self) -> str: |
| | return f"<UniformResourceIdentifier(value={self.value!r})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, UniformResourceIdentifier): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class DirectoryName(GeneralName): |
| | def __init__(self, value: Name) -> None: |
| | if not isinstance(value, Name): |
| | raise TypeError("value must be a Name") |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> Name: |
| | return self._value |
| |
|
| | def __repr__(self) -> str: |
| | return f"<DirectoryName(value={self.value})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, DirectoryName): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class RegisteredID(GeneralName): |
| | def __init__(self, value: ObjectIdentifier) -> None: |
| | if not isinstance(value, ObjectIdentifier): |
| | raise TypeError("value must be an ObjectIdentifier") |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> ObjectIdentifier: |
| | return self._value |
| |
|
| | def __repr__(self) -> str: |
| | return f"<RegisteredID(value={self.value})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, RegisteredID): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class IPAddress(GeneralName): |
| | def __init__(self, value: _IPAddressTypes) -> None: |
| | if not isinstance( |
| | value, |
| | ( |
| | ipaddress.IPv4Address, |
| | ipaddress.IPv6Address, |
| | ipaddress.IPv4Network, |
| | ipaddress.IPv6Network, |
| | ), |
| | ): |
| | raise TypeError( |
| | "value must be an instance of ipaddress.IPv4Address, " |
| | "ipaddress.IPv6Address, ipaddress.IPv4Network, or " |
| | "ipaddress.IPv6Network" |
| | ) |
| |
|
| | self._value = value |
| |
|
| | @property |
| | def value(self) -> _IPAddressTypes: |
| | return self._value |
| |
|
| | def _packed(self) -> bytes: |
| | if isinstance( |
| | self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) |
| | ): |
| | return self.value.packed |
| | else: |
| | return ( |
| | self.value.network_address.packed + self.value.netmask.packed |
| | ) |
| |
|
| | def __repr__(self) -> str: |
| | return f"<IPAddress(value={self.value})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, IPAddress): |
| | return NotImplemented |
| |
|
| | return self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash(self.value) |
| |
|
| |
|
| | class OtherName(GeneralName): |
| | def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: |
| | if not isinstance(type_id, ObjectIdentifier): |
| | raise TypeError("type_id must be an ObjectIdentifier") |
| | if not isinstance(value, bytes): |
| | raise TypeError("value must be a binary string") |
| |
|
| | self._type_id = type_id |
| | self._value = value |
| |
|
| | @property |
| | def type_id(self) -> ObjectIdentifier: |
| | return self._type_id |
| |
|
| | @property |
| | def value(self) -> bytes: |
| | return self._value |
| |
|
| | def __repr__(self) -> str: |
| | return f"<OtherName(type_id={self.type_id}, value={self.value!r})>" |
| |
|
| | def __eq__(self, other: object) -> bool: |
| | if not isinstance(other, OtherName): |
| | return NotImplemented |
| |
|
| | return self.type_id == other.type_id and self.value == other.value |
| |
|
| | def __hash__(self) -> int: |
| | return hash((self.type_id, self.value)) |
| |
|