Source code for mimesis.providers.internet

"""Provides data related to internet."""

import typing as t
import urllib.error
import urllib.parse
import urllib.request
from base64 import b64encode
from ipaddress import IPv4Address, IPv6Address

from mimesis.datasets import (
    CONTENT_ENCODING_DIRECTIVES,
    CORS_OPENER_POLICIES,
    CORS_RESOURCE_POLICIES,
    HTTP_METHODS,
    HTTP_SERVERS,
    HTTP_STATUS_CODES,
    HTTP_STATUS_MSGS,
    PUBLIC_DNS,
    TLD,
    USER_AGENTS,
    USERNAMES,
)
from mimesis.enums import (
    DSNType,
    Locale,
    MimeType,
    PortRange,
    TLDType,
    URLScheme,
)
from mimesis.providers.base import BaseProvider
from mimesis.providers.code import Code
from mimesis.providers.date import Datetime
from mimesis.providers.file import File
from mimesis.providers.text import Text
from mimesis.types import Keywords

__all__ = ["Internet"]


[docs] class Internet(BaseProvider): """Class for generating data related to the internet.""" _MAX_IPV4: t.Final[int] = (2**32) - 1 _MAX_IPV6: t.Final[int] = (2**128) - 1
[docs] def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: """Initialize attributes. :param args: Arguments. :param kwargs: Keyword arguments. """ super().__init__(*args, **kwargs) self._file = File( seed=self.seed, random=self.random, ) self._code = Code( seed=self.seed, random=self.random, ) self._text = Text( locale=Locale.EN, seed=self.seed, random=self.random, ) self._datetime = Datetime( locale=Locale.EN, seed=self.seed, random=self.random, )
class Meta: name = "internet"
[docs] def content_type(self, mime_type: MimeType | None = None) -> str: """Generates a random HTTP content type. :return: Content type. :Example: application/json """ return self._file.mime_type(type_=mime_type)
[docs] def dsn(self, dsn_type: DSNType | None = None, **kwargs: t.Any) -> str: """Generates a random DSN (Data Source Name). :param dsn_type: DSN type. :param kwargs: Additional keyword-arguments for hostname method. """ hostname = self.hostname(**kwargs) scheme, port = self.validate_enum(dsn_type, DSNType) return f"{scheme}://{hostname}:{port}"
[docs] def http_status_message(self) -> str: """Generates a random HTTP status message. :return: HTTP status message. :Example: 200 OK """ return self.random.choice(HTTP_STATUS_MSGS)
[docs] def http_status_code(self) -> int: """Generates a random HTTP status code. :return: HTTP status. :Example: 200 """ return self.random.choice(HTTP_STATUS_CODES)
[docs] def http_method(self) -> str: """Generates a random HTTP method. :return: HTTP method. :Example: POST """ return self.random.choice(HTTP_METHODS)
[docs] def ip_v4_object(self) -> IPv4Address: """Generates a random :py:class:`ipaddress.IPv4Address` object. :return: :py:class:`ipaddress.IPv4Address` object. """ return IPv4Address( self.random.randint(0, self._MAX_IPV4), )
[docs] def ip_v4_with_port(self, port_range: PortRange = PortRange.ALL) -> str: """Generates a random IPv4 address as string. :param port_range: PortRange enum object. :return: IPv4 address as string. :Example: 19.121.223.58:8000 """ addr = self.ip_v4() port = self.port(port_range) return f"{addr}:{port}"
[docs] def ip_v4(self) -> str: """Generates a random IPv4 address as string. :Example: 19.121.223.58 """ return str(self.ip_v4_object())
[docs] def ip_v6_object(self) -> IPv6Address: """Generates random :py:class:`ipaddress.IPv6Address` object. :return: :py:class:`ipaddress.IPv6Address` object. """ return IPv6Address( self.random.randint( 0, self._MAX_IPV6, ), )
[docs] def ip_v6(self) -> str: """Generates a random IPv6 address as string. :return: IPv6 address string. :Example: 2001:c244:cf9d:1fb1:c56d:f52c:8a04:94f3 """ return str(self.ip_v6_object())
[docs] def mac_address(self) -> str: """Generates a random MAC address. :return: Random MAC address. :Example: 00:16:3e:25:e7:f1 """ mac_hex = [ 0x00, 0x16, 0x3E, self.random.randint(0x00, 0x7F), self.random.randint(0x00, 0xFF), self.random.randint(0x00, 0xFF), ] mac = [f"{x:02x}" for x in mac_hex] return ":".join(mac)
[docs] @staticmethod def stock_image_url( width: int | str = 1920, height: int | str = 1080, keywords: Keywords | None = None, ) -> str: """Generates a random stock image URL hosted on Unsplash. See «Random search term» on https://source.unsplash.com/ for more details. :param width: Width of the image. :param height: Height of the image. :param keywords: Sequence of search keywords. :return: URL of the image. """ if keywords is not None: keywords_str = ",".join(keywords) else: keywords_str = "" return f"https://source.unsplash.com/{width}x{height}?{keywords_str}"
[docs] def hostname( self, tld_type: TLDType | None = None, subdomains: list[str] | None = None, ) -> str: """Generates a random hostname without a scheme. :param tld_type: TLDType. :param subdomains: List of subdomains (make sure they are valid). :return: Hostname. """ tld = self.tld(tld_type=tld_type) host = self.random.choice(USERNAMES) if subdomains: subdomain = self.random.choice(subdomains) host = f"{subdomain}.{host}" return f"{host}{tld}"
[docs] def url( self, scheme: URLScheme | None = URLScheme.HTTPS, port_range: PortRange | None = None, tld_type: TLDType | None = None, subdomains: list[str] | None = None, ) -> str: """Generates a random URL. :param scheme: The scheme. :param port_range: PortRange enum object. :param tld_type: TLDType. :param subdomains: List of subdomains (make sure they are valid). :return: URL. """ host = self.hostname(tld_type, subdomains) url_scheme = self.validate_enum(scheme, URLScheme) url = f"{url_scheme}://{host}" if port_range is not None: url = f"{url}:{self.port(port_range)}" return f"{url}/"
[docs] def uri( self, scheme: URLScheme | None = URLScheme.HTTPS, tld_type: TLDType | None = None, subdomains: list[str] | None = None, query_params_count: int | None = None, ) -> str: """Generates a random URI. :param scheme: Scheme. :param tld_type: TLDType. :param subdomains: List of subdomains (make sure they are valid). :param query_params_count: Query params. :return: URI. """ directory = ( self._datetime.date(start=2010, end=self._datetime._CURRENT_YEAR) .strftime("%Y-%m-%d") .replace("-", "/") ) url = self.url(scheme, None, tld_type, subdomains) uri = f"{url}{directory}/{self.slug()}" if query_params_count: uri += f"?{self.query_string(query_params_count)}" return uri
[docs] def query_string(self, length: int | None = None) -> str: """Generates an arbitrary query string of given length. :param length: Length of query string. :return: Query string. """ return urllib.parse.urlencode(self.query_parameters(length))
[docs] def query_parameters(self, length: int | None = None) -> dict[str, str]: """Generates an arbitrary query parameters as a dict. :param length: Length of query parameters dictionary (maximum is 32). :return: Dict of query parameters. """ def pick_unique_words(quantity: int = 5) -> list[str]: words: set[str] = set() while len(words) != quantity: words.add(self._text.word()) return list(words) if not length: length = self.random.randint(1, 10) if length > 32: raise ValueError("Maximum allowed length of query parameters is 32.") return dict(zip(pick_unique_words(length), self._text.words(length)))
[docs] def top_level_domain(self, tld_type: TLDType = TLDType.CCTLD) -> str: """Generates random top level domain. :param tld_type: Enum object :class:`enums.TLDType` :return: Top level domain. :raises NonEnumerableError: if tld_type not in :class:`enums.TLDType`. """ key = self.validate_enum(item=tld_type, enum=TLDType) return self.random.choice(TLD[key])
[docs] def tld(self, *args: t.Any, **kwargs: t.Any) -> str: """Generates a random TLD. An alias for :meth:`top_level_domain` """ return self.top_level_domain(*args, **kwargs)
[docs] def user_agent(self) -> str: """Get a random user agent. :return: User agent. :Example: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1 """ return self.random.choice(USER_AGENTS)
[docs] def port(self, port_range: PortRange = PortRange.ALL) -> int: """Generates a random port. :param port_range: PortRange enum object. :return: Port number. :raises NonEnumerableError: if port_range is not in PortRange. :Example: 8080 """ rng = self.validate_enum(port_range, PortRange) return self.random.randint(*rng)
[docs] def path(self, *args: t.Any, **kwargs: t.Any) -> str: """Generates a random path. :param args: Arguments to pass to :meth:`slug`. :param kwargs: Keyword arguments to pass to :meth:`slug`. :return: Path. """ return self.slug(*args, **kwargs).replace("-", "/")
[docs] def slug(self, parts_count: int | None = None) -> str: """Generates a random slug of given parts count. :param parts_count: Slug's parts count. :return: Slug. """ if not parts_count: parts_count = self.random.randint(2, 12) if parts_count > 12: raise ValueError("Slug's parts count must be <= 12") if parts_count < 2: raise ValueError("Slug must contain more than 2 parts") return "-".join(self._text.words(parts_count))
[docs] def public_dns(self) -> str: """Generates a random public DNS. :Example: 1.1.1.1 """ return self.random.choice(PUBLIC_DNS)
[docs] def http_response_headers(self) -> dict[str, t.Any]: """Generates a random HTTP response headers. The following headers are included: - Allow - Age - Server - Content-Type - X-Request-ID - Content-Language - Content-Location - Set-Cookie - Upgrade-Insecure-Requests - X-Content-Type-Options - X-XSS-Protection - Connection - X-Frame-Options - Content-Encoding - Cross-Origin-Opener-Policy - Cross-Origin-Resource-Policy - Strict-Transport-Security :return: Response headers as dict. """ max_age = self.random.randint(0, 60 * 60 * 15) cookie_attributes = [ "Secure", "HttpOnly", "SameSite=Lax", "SameSite=Strict", f"Max-Age={max_age}", f"Domain={self.hostname()}", ] k, v = self._text.words(quantity=2) cookie_attr = self.random.choice(cookie_attributes) csrf_token = b64encode(self.random.randbytes(n=32)).decode() cookie_value = f"csrftoken={csrf_token}; {k}={v}; {cookie_attr}" headers = { "Allow": "*", "Age": max_age, "Server": self.random.choice(HTTP_SERVERS), "Content-Type": self._file.mime_type(), "X-Request-ID": self.random.randbytes(16).hex(), "Content-Language": self._code.locale_code(), "Content-Location": self.path(parts_count=4), "Set-Cookie": cookie_value, "Upgrade-Insecure-Requests": 1, "X-Content-Type-Options": "nosniff", "X-XSS-Protection": 1, "Connection": self.random.choice(["close", "keep-alive"]), "X-Frame-Options": self.random.choice(["DENY", "SAMEORIGIN"]), "Content-Encoding": self.random.choice(CONTENT_ENCODING_DIRECTIVES), "Cross-Origin-Opener-Policy": self.random.choice(CORS_OPENER_POLICIES), "Cross-Origin-Resource-Policy": self.random.choice(CORS_RESOURCE_POLICIES), "Strict-Transport-Security": f"max-age={max_age}", } return headers
[docs] def http_request_headers(self) -> dict[str, t.Any]: """Generates a random HTTP request headers. The following headers are included: - Referer - Authorization - Cookie - User-Agent - X-CSRF-Token - Content-Type - Content-Length - Connection - Cache-Control - Accept - Host - Accept-Language :return: Request headers as dict. """ k, v = self._text.words(quantity=2) max_age = self.random.randint(0, 60 * 60 * 15) token = b64encode(self.random.randbytes(64)).hex() csrf_token = b64encode(self.random.randbytes(n=32)).decode() headers = { "Referer": self.uri(), "Authorization": f"Bearer {token}", "Cookie": f"csrftoken={csrf_token}; {k}={v}", "User-Agent": self.user_agent(), "X-CSRF-Token": b64encode(self.random.randbytes(32)).hex(), "Content-Type": self._file.mime_type(), "Content-Length": self.random.randint(0, 10000), "Connection": self.random.choice(["close", "keep-alive"]), "Cache-Control": self.random.choice( [ "no-cache", "no-store", "must-revalidate", "public", "private", f"max-age={max_age}", ] ), "Accept": self.random.choice( [ "*/*", self._file.mime_type(), ] ), "Host": self.hostname(), "Accept-Language": self.random.choice( [ "*", self._code.locale_code(), ] ), } return headers