codekingpro/portable-devtools
114k
1import ssl2from typing import NamedTuple, Optional3 4# noinspection PyPackageRequirements5from urllib3.util.ssl_ import (6 create_urllib3_context,7 resolve_ssl_version,8)9 10from .adapters import HTTPAdapter11from .compat import ensure_default_certs_loaded12 13 14SSL_VERSION_ARG_MAPPING = {15 'ssl2.3': 'PROTOCOL_SSLv23',16 'ssl3': 'PROTOCOL_SSLv3',17 'tls1': 'PROTOCOL_TLSv1',18 'tls1.1': 'PROTOCOL_TLSv1_1',19 'tls1.2': 'PROTOCOL_TLSv1_2',20 'tls1.3': 'PROTOCOL_TLSv1_3',21}22AVAILABLE_SSL_VERSION_ARG_MAPPING = {23 arg: getattr(ssl, constant_name)24 for arg, constant_name in SSL_VERSION_ARG_MAPPING.items()25 if hasattr(ssl, constant_name)26}27 28 29class HTTPieCertificate(NamedTuple):30 cert_file: Optional[str] = None31 key_file: Optional[str] = None32 key_password: Optional[str] = None33 34 def to_raw_cert(self):35 """Synthesize a requests-compatible (2-item tuple of cert and key file)36 object from HTTPie's internal representation of a certificate."""37 return self.cert_file, self.key_file38 39 40class HTTPieHTTPSAdapter(HTTPAdapter):41 def __init__(42 self,43 verify: bool,44 ssl_version: str = None,45 ciphers: str = None,46 **kwargs47 ):48 self._ssl_context = self._create_ssl_context(49 verify=verify,50 ssl_version=ssl_version,51 ciphers=ciphers,52 )53 super().__init__(**kwargs)54 55 def init_poolmanager(self, *args, **kwargs):56 kwargs['ssl_context'] = self._ssl_context57 return super().init_poolmanager(*args, **kwargs)58 59 def proxy_manager_for(self, *args, **kwargs):60 kwargs['ssl_context'] = self._ssl_context61 return super().proxy_manager_for(*args, **kwargs)62 63 def cert_verify(self, conn, url, verify, cert):64 if isinstance(cert, HTTPieCertificate):65 conn.key_password = cert.key_password66 cert = cert.to_raw_cert()67 68 return super().cert_verify(conn, url, verify, cert)69 70 @staticmethod71 def _create_ssl_context(72 verify: bool,73 ssl_version: str = None,74 ciphers: str = None,75 ) -> 'ssl.SSLContext':76 ssl_context = create_urllib3_context(77 ciphers=ciphers,78 ssl_version=resolve_ssl_version(ssl_version),79 # Since we are using a custom SSL context, we need to pass this80 # here manually, even though it’s also passed to the connection81 # in `super().cert_verify()`.82 cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE83 )84 ensure_default_certs_loaded(ssl_context)85 return ssl_context86 87 @classmethod88 def get_default_ciphers_names(cls):89 return [cipher['name'] for cipher in cls._create_ssl_context(verify=False).get_ciphers()]90 91 92def _is_key_file_encrypted(key_file):93 """Detects if a key file is encrypted or not.94 95 Copy of the internal urllib function (urllib3.util.ssl_)"""96 97 with open(key_file, "r") as f:98 for line in f:99 # Look for Proc-Type: 4,ENCRYPTED100 if "ENCRYPTED" in line:101 return True102 103 return False104 105 106# We used to import the default set of TLS ciphers from urllib3, but they removed it.107# Instead, now urllib3 uses the list of ciphers configured by the system.108# <https://github.com/httpie/cli/pull/1501>109DEFAULT_SSL_CIPHERS_STRING = ':'.join(HTTPieHTTPSAdapter.get_default_ciphers_names())110 