From 7cffdfc7aabab48489b4c1dff26b2a9b1f9b881b Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Tue, 7 Nov 2023 10:46:33 +0100 Subject: [PATCH] Add local SSL CA check (#453) --- .pylintrc | 2 ++ pyoverkiz/client.py | 20 ++++++++++++++++++-- pyoverkiz/overkiz-root-ca-2048.crt | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 pyoverkiz/overkiz-root-ca-2048.crt diff --git a/.pylintrc b/.pylintrc index 52e2a378..48762ea1 100644 --- a/.pylintrc +++ b/.pylintrc @@ -24,3 +24,5 @@ disable= fixme, pointless-string-statement, redefined-builtin + +max-module-lines=2000 diff --git a/pyoverkiz/client.py b/pyoverkiz/client.py index 187f3f94..6dd1a8d5 100644 --- a/pyoverkiz/client.py +++ b/pyoverkiz/client.py @@ -3,6 +3,8 @@ import asyncio import datetime +import os +import ssl import urllib.parse from collections.abc import Mapping from json import JSONDecodeError @@ -110,6 +112,7 @@ class OverkizClient: _refresh_token: str | None = None _expires_in: datetime.datetime | None = None _access_token: str | None = None + _ssl_context: ssl.SSLContext | None = None def __init__( self, @@ -142,6 +145,12 @@ def __init__( if LOCAL_API_PATH in self.server.endpoint: self.api_type = APIType.LOCAL + # To avoid security issues, we add the following authority to + # our HTTPS client trust store: https://ca.overkiz.com/overkiz-root-ca-2048.crt + self._ssl_context = ssl.create_default_context( + cafile=os.path.dirname(os.path.realpath(__file__)) + + "/overkiz-root-ca-2048.crt" + ) else: self.api_type = APIType.CLOUD @@ -846,6 +855,7 @@ async def __get(self, path: str) -> Any: async with self.session.get( f"{self.server.endpoint}{path}", headers=headers, + ssl_context=self._ssl_context, ) as response: await self.check_response(response) return await response.json() @@ -861,7 +871,11 @@ async def __post( headers["Authorization"] = f"Bearer {self._access_token}" async with self.session.post( - f"{self.server.endpoint}{path}", data=data, json=payload, headers=headers + f"{self.server.endpoint}{path}", + data=data, + json=payload, + headers=headers, + ssl_context=self._ssl_context, ) as response: await self.check_response(response) return await response.json() @@ -876,7 +890,9 @@ async def __delete(self, path: str) -> None: headers["Authorization"] = f"Bearer {self._access_token}" async with self.session.delete( - f"{self.server.endpoint}{path}", headers=headers + f"{self.server.endpoint}{path}", + headers=headers, + ssl_context=self._ssl_context, ) as response: await self.check_response(response) diff --git a/pyoverkiz/overkiz-root-ca-2048.crt b/pyoverkiz/overkiz-root-ca-2048.crt new file mode 100644 index 00000000..9d9adef8 --- /dev/null +++ b/pyoverkiz/overkiz-root-ca-2048.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIJAOvswclbF4QnMA0GCSqGSIb3DQEBCwUAMEsxEDAOBgNV +BAoTB092ZXJraXoxEDAOBgNVBAsTB1Jvb3QgQ0ExGDAWBgNVBAMTD092ZXJraXog +Um9vdCBDQTELMAkGA1UEBhMCRlIwHhcNMTYwNDI3MTI1ODE1WhcNMzYwNDI3MTI1 +ODE1WjBLMRAwDgYDVQQKEwdPdmVya2l6MRAwDgYDVQQLEwdSb290IENBMRgwFgYD +VQQDEw9PdmVya2l6IFJvb3QgQ0ExCzAJBgNVBAYTAkZSMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAsszRfbcNCEoD9ZfzTbXfuMK8CrXGqBR/ZOCk4guN +aRKqZ/rLQm3V6Q+dlJ/8qle5J3KN5bZmqT4qXKHwJsaOiLfPyAptSM6vuIlls2N+ +UsKkv3m5+gTyLaSGMS4wh2GoOCa21V9t5wYUQnoFaQByVNyl+kkrWLpKw5gQasU0 +xkVsjAVKgkkb3puBl7sZgiSoz97I9U9JUkg3spH0I84CZRI+JejioDHvkZEyf83j ++QFxSTV/hZkUwUY/X0zt2dTZuliCTePeCdANryo6+9TbBp98j/SB1s59FcO8NSSK +sV07rTFlM9/soko2/J0aTtXHE86wFq7vfFVZzZxsQpIBbwIDAQABoyMwITAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +GU7xUWlZZEVnEK0k3Z1FoRl9xA7cLOiDVCQ5qQDFfQgGpMtXv1PKsQNZ6T6tZN3d +bdzsqcQXtLhXknz6aGBZNR4g6liQhVuCaiyURaI+LM2KuSZnbixs3+1SPBvxHrJh +/gOsxctxq+0DALnOK9qbGl6N5DtjM/EC5Qve71c+UVTEcJjJ3L2S1Ne+PxDOJuUC +JsOLUk96G+uLn6CQB5Wu8fYrkWAjF3yrxkCoZCqOvVrnbL77vXmz2mlqNHSJt3Ur +ndWJLVvrRFKdSG6WiNCh/Q+ARQAorN60JD9x8+IyXRGvlZl7KVeRduE2rjZuom7h +QLMnmaF+oFW5mnhh9gu6Gg== +-----END CERTIFICATE-----