11# The MIT License (MIT)
22#
3- # Copyright (c) 2016-2022 Frederic Guillot
3+ # Copyright (c) Frederic Guillot
44#
55# Permission is hereby granted, free of charge, to any person obtaining a copy
66# of this software and associated documentation files (the "Software"), to deal
2424import base64
2525import functools
2626import asyncio
27+ import ssl
28+ from typing import Dict , Optional
2729from urllib import request as http
2830
2931
@@ -52,12 +54,14 @@ class Client:
5254 """
5355
5456 def __init__ (self ,
55- url ,
56- username ,
57- password ,
58- auth_header = DEFAULT_AUTH_HEADER ,
59- cafile = None ,
60- loop = None ):
57+ url : str ,
58+ username : str ,
59+ password : str ,
60+ auth_header : str = DEFAULT_AUTH_HEADER ,
61+ cafile : Optional [str ] = None ,
62+ insecure : bool = False ,
63+ ignore_hostname_verification : bool = False ,
64+ loop : Optional [asyncio .AbstractEventLoop ] = None ):
6165 """
6266 Constructor
6367
@@ -66,22 +70,26 @@ def __init__(self,
6670 username: API username or real username
6771 password: API token or user password
6872 auth_header: API HTTP header
69- cafile: path to a custom CA certificate
70- loop: an asyncio event loop. Default: asyncio.get_event_loop()
73+ cafile: Path to a custom CA certificate
74+ insecure: Ignore SSL certificate errors and ignore hostname mismatches
75+ ignore_hostname_verification: Ignore SSL certificate hostname verification
76+ loop: An asyncio event loop. Default: asyncio.get_event_loop()
7177 """
7278 self ._url = url
7379 self ._username = username
7480 self ._password = password
7581 self ._auth_header = auth_header
7682 self ._cafile = cafile
83+ self ._insecure = insecure
84+ self ._ignore_hostname_verification = ignore_hostname_verification
7785
7886 if not loop :
7987 try :
8088 self ._event_loop = asyncio .get_event_loop ()
8189 except RuntimeError :
8290 self ._event_loop = asyncio .new_event_loop ()
8391
84- def __getattr__ (self , name ):
92+ def __getattr__ (self , name : str ):
8593 if self .is_async_method_name (name ):
8694 async def function (* args , ** kwargs ):
8795 return await self ._event_loop .run_in_executor (
@@ -96,20 +104,20 @@ def function(*args, **kwargs):
96104 return function
97105
98106 @staticmethod
99- def is_async_method_name (funcname ) :
107+ def is_async_method_name (funcname : str ) -> bool :
100108 return funcname .endswith (ASYNC_FUNCNAME_MARKER )
101109
102110 @staticmethod
103- def get_funcname_from_async_name (funcname ) :
111+ def get_funcname_from_async_name (funcname : str ) -> str :
104112 return funcname [:len (funcname ) - len (ASYNC_FUNCNAME_MARKER )]
105113
106114 @staticmethod
107- def _to_camel_case (snake_str ) :
115+ def _to_camel_case (snake_str : str ) -> str :
108116 components = snake_str .split ('_' )
109117 return components [0 ] + '' .join (x .title () for x in components [1 :])
110118
111119 @staticmethod
112- def _parse_response (response ):
120+ def _parse_response (response : bytes ):
113121 try :
114122 body = json .loads (response .decode (errors = 'ignore' ))
115123
@@ -121,20 +129,26 @@ def _parse_response(response):
121129 except ValueError :
122130 return None
123131
124- def _do_request (self , headers , body ):
132+ def _do_request (self , headers : Dict [ str , str ], body : Dict ):
125133 try :
126134 request = http .Request (self ._url ,
127135 headers = headers ,
128136 data = json .dumps (body ).encode ())
129- if self ._cafile :
130- response = http .urlopen (request , cafile = self ._cafile ).read ()
131- else :
132- response = http .urlopen (request ).read ()
137+
138+ ssl_context = ssl .create_default_context (cafile = self ._cafile )
139+ if self ._insecure :
140+ ssl_context .check_hostname = False
141+ ssl_context .verify_mode = ssl .CERT_NONE
142+
143+ if self ._ignore_hostname_verification :
144+ ssl_context .check_hostname = False
145+
146+ response = http .urlopen (request , context = ssl_context ).read ()
133147 except Exception as e :
134148 raise ClientError (str (e ))
135149 return self ._parse_response (response )
136150
137- def execute (self , method , ** kwargs ):
151+ def execute (self , method : str , ** kwargs ):
138152 """
139153 Call remote API procedure
140154
0 commit comments