DeepLcom / deepl-python

Official Python library for the DeepL language translation API.
MIT License
1.06k stars 75 forks source link

Allow usage of custom CA Certificates or Disable SSL verification #60

Closed andrefloriani closed 1 year ago

andrefloriani commented 1 year ago

In enterprise environments it is usual to have custom "Intermediate certificates" from different data security implementations, such as ZScaler, and will cause any requests to the DeepL engine to fail due to SSL verification error.

Usually these certificates are retrievable from the local OS (Windows Certificates Store or Linux/Mac certs file).

This suggestion adds a new parameter to the Translator and HttpClient classes enabling the user to pass it to the verify argument of the requests.Session object.

Note: setting the environment variables REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE does not solve the issue, as requests.Session.send and requests.Session.__init__ currently ignore OS environment variables. They are only considered in direct requests without a Session via requests.request and its dependant functions such as requests.get, requests.post, etc.

Modifications to translator.py > Translator.__init__:

def __init__(
        self,
        auth_key: str,
        *,
        server_url: Optional[str] = None,
        proxy: Union[Dict, str, None] = None,
        **verify_ssl:bool = True,** #<--------- Custom code added -> new 'verify_ssl' parameter --------->#
        skip_language_check: bool = False,
    ):
        if not auth_key:
            raise ValueError("auth_key must not be empty")

        if server_url is None:
            server_url = (
                self._DEEPL_SERVER_URL_FREE
                if util.auth_key_is_free_account(auth_key)
                else self._DEEPL_SERVER_URL
            )

        self._server_url = server_url
        self._client = http_client.HttpClient(proxy**, verify_ssl**) #<--------- Custom code added to use local certs, when given --------->#
        self.headers = {"Authorization": f"DeepL-Auth-Key {auth_key}"}

Modifications to http_client.py > HttpClient.__init__:

def __init__(self, proxy: Union[Dict, str, None] = None**, verify_ssl:bool = True**): #<--------- Custom code added -> new 'verify' parameter --------->
        self._session = requests.Session()

        if proxy:
            if isinstance(proxy, str):
                proxy = {"http": proxy, "https": proxy}
            if not isinstance(proxy, dict):
                raise ValueError(
                    "proxy may be specified as a URL string or dictionary "
                    "containing URL strings for the http and https keys."
                )
            self._session.proxies.update(proxy)

        # ------------------------------------------------------- #
        # Custom code added                                       #
        # Allows usage of Local Certificates for SSL verification #
        from os import path
        if (type(verify_ssl)==bool) or ((type(verify_ssl)==str) and path.exists(verify_ssl)):
            self._session.verify = verify_ssl
        del path
        # ------------------------------------------------------- #

        self._session.headers = {"User-Agent": user_agent}
        pass
daniel-jones-deepl commented 1 year ago

Hi @andrefloriani Andre, apologies that it took so long to reply to this issue.

Good suggestion, we're going to add an option for this soon.

daniel-jones-deepl commented 1 year ago

This is implemented in v1.14.0.

Please be aware that we didn't implement the path verification like you have in your suggestion -- we preferred to pass the user-argument directly to requests so long as it is not None.