We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Berlin Recycling broken due to SSL misconfiguration
Berlin Recycling is currently broken and fails with an `SSLCertVerificationError`:

> Logger: waste_collection_schedule.scraper
> Source: custom_components/waste_collection_schedule/waste_collection_schedule/scraper.py:118
> Integration: waste_collection_schedule (documentation)
> First occurred: 22. März 2022, 16:39:19 (2 occurrences)
> Last logged: 01:12:00
> 
> fetch failed for source Berline Recycling: Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py", line 703, in urlopen httplib_response = self._make_request( File "/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py", line 386, in _make_request self._validate_conn(conn) File "/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py", line 1040, in _validate_conn conn.connect() File "/usr/local/lib/python3.9/site-packages/urllib3/connection.py", line 414, in connect self.sock = ssl_wrap_socket( File "/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py", line 449, in ssl_wrap_socket ssl_sock = _ssl_wrap_socket_impl( File "/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py", line 493, in _ssl_wrap_socket_impl return ssl_context.wrap_socket(sock, server_hostname=server_hostname) File "/usr/local/lib/python3.9/ssl.py", line 500, in wrap_socket return self.sslsocket_class._create( File "/usr/local/lib/python3.9/ssl.py", line 1040, in _create self.do_handshake() File "/usr/local/lib/python3.9/ssl.py", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/requests/adapters.py", line 440, in send resp = conn.urlopen( File "/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py", line 785, in urlopen retries = retries.increment( File "/usr/local/lib/python3.9/site-packages/urllib3/util/retry.py", line 592, in increment raise MaxRetryError(_pool, url, error or ResponseError(cause)) urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='kundenportal.berlin-recycling.de', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)'))) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/config/custom_components/waste_collection_schedule/waste_collection_schedule/scraper.py", line 116, in fetch entries = self._source.fetch() File "/config/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py", line 48, in fetch r = session.get(SERVICE_URL, allow_redirects=False) File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 542, in get return self.request('GET', url, **kwargs) File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 529, in request resp = self.send(prep, **send_kwargs) File "/usr/local/lib/python3.9/site-packages/requests/sessions.py", line 645, in send r = adapter.send(request, **kwargs) File "/usr/local/lib/python3.9/site-packages/requests/adapters.py", line 517, in send raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='kundenportal.berlin-recycling.de', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)')))

Seems the reason is https://kundenportal.berlin-recycling.de has a misconfigured HTTPS server [which is not sending the intermediate certificate](https://www.ssllabs.com/ssltest/analyze.html?d=kundenportal.berlin-recycling.de) ([Starfield Secure Certificate Authority - G2](https://certs.starfieldtech.com/repository/)). Unlike browsers, python [does not support](https://bugs.python.org/issue18617) automatic fetching of missing intermediates.

I think an option to avoid setting `verify = False` on the request would be pinning the CAs and shipping the certificates with the project.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py`
Content:
```
1 import json
2 from datetime import datetime
3 from html.parser import HTMLParser
4 
5 import requests
6 from waste_collection_schedule import Collection  # type: ignore[attr-defined]
7 
8 TITLE = "Berline Recycling"
9 DESCRIPTION = "Source for Berlin Recycling waste collection."
10 URL = "https://berlin-recycling.de"
11 TEST_CASES = {
12     "Germanenstrasse": {
13         "username": "!secret berlin_recycling_username",
14         "password": "!secret berlin_recycling_password",
15     },
16 }
17 
18 
19 # Parser for HTML input (hidden) text
20 class HiddenInputParser(HTMLParser):
21     def __init__(self):
22         super().__init__()
23         self._args = {}
24 
25     @property
26     def args(self):
27         return self._args
28 
29     def handle_starttag(self, tag, attrs):
30         if tag == "input":
31             d = dict(attrs)
32             if str(d["type"]).lower() == "hidden":
33                 self._args[d["name"]] = d["value"] if "value" in d else ""
34 
35 
36 SERVICE_URL = "https://kundenportal.berlin-recycling.de/"
37 
38 
39 class Source:
40     def __init__(self, username, password):
41         self._username = username
42         self._password = password
43 
44     def fetch(self):
45         session = requests.session()
46 
47         # first get returns session specific url
48         r = session.get(SERVICE_URL, allow_redirects=False)
49 
50         # get session id's
51         r = session.get(r.url)
52 
53         parser = HiddenInputParser()
54         parser.feed(r.text)
55         args = parser.args
56         args["__EVENTTARGET"] = "btnLog"
57         args["__EVENTARGUMENT"] = None
58         args["Username"] = self._username
59         args["Password"] = self._password
60 
61         # login
62         r = session.post(r.url, data=args)
63         serviceUrl = r.url
64 
65         request_data = {"withhtml": "true"}
66         r = session.post(serviceUrl + "/GetDashboard", json=request_data)
67 
68         request_data = {"datasettable": "ENWIS_ABFUHRKALENDER"}
69         r = session.post(serviceUrl + "/ChangeDatasetTable", json=request_data)
70 
71         request_data = {
72             "datasettablecode": "ENWIS_ABFUHRKALENDER",
73             "startindex": 0,
74             "searchtext": "",
75             "rangefilter": "",
76             "ordername": "",
77             "orderdir": "",
78             "ClientParameters": "",
79             "headrecid": "",
80         }
81         r = session.post(serviceUrl + "/GetDatasetTableHead", json=request_data)
82 
83         data = json.loads(r.text)
84         # load json again, because response is double coded
85         data = json.loads(data["d"])
86 
87         entries = []
88         for d in data["data"]:
89             date = datetime.strptime(d["Task Date"], "%Y-%m-%d").date()
90             entries.append(Collection(date, d["Material Description"]))
91         return entries
92
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py
@@ -45,7 +45,7 @@
         session = requests.session()
 
         # first get returns session specific url
-        r = session.get(SERVICE_URL, allow_redirects=False)
+        r = session.get(SERVICE_URL, allow_redirects=False, verify=False)
 
         # get session id's
         r = session.get(r.url)

{"golden_diff": "diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py\n--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py\n+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py\n@@ -45,7 +45,7 @@\n         session = requests.session()\n \n         # first get returns session specific url\n-        r = session.get(SERVICE_URL, allow_redirects=False)\n+        r = session.get(SERVICE_URL, allow_redirects=False, verify=False)\n \n         # get session id's\n         r = session.get(r.url)\n", "issue": "Berlin Recycling broken due to SSL misconfiguration\nBerlin Recycling is currently broken and fails with an `SSLCertVerificationError`:\r\n\r\n> Logger: waste_collection_schedule.scraper\r\n> Source: custom_components/waste_collection_schedule/waste_collection_schedule/scraper.py:118\r\n> Integration: waste_collection_schedule (documentation)\r\n> First occurred: 22. M\u00e4rz 2022, 16:39:19 (2 occurrences)\r\n> Last logged: 01:12:00\r\n> \r\n> fetch failed for source Berline Recycling: Traceback (most recent call last): File \"/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py\", line 703, in urlopen httplib_response = self._make_request( File \"/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py\", line 386, in _make_request self._validate_conn(conn) File \"/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py\", line 1040, in _validate_conn conn.connect() File \"/usr/local/lib/python3.9/site-packages/urllib3/connection.py\", line 414, in connect self.sock = ssl_wrap_socket( File \"/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py\", line 449, in ssl_wrap_socket ssl_sock = _ssl_wrap_socket_impl( File \"/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py\", line 493, in _ssl_wrap_socket_impl return ssl_context.wrap_socket(sock, server_hostname=server_hostname) File \"/usr/local/lib/python3.9/ssl.py\", line 500, in wrap_socket return self.sslsocket_class._create( File \"/usr/local/lib/python3.9/ssl.py\", line 1040, in _create self.do_handshake() File \"/usr/local/lib/python3.9/ssl.py\", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/usr/local/lib/python3.9/site-packages/requests/adapters.py\", line 440, in send resp = conn.urlopen( File \"/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py\", line 785, in urlopen retries = retries.increment( File \"/usr/local/lib/python3.9/site-packages/urllib3/util/retry.py\", line 592, in increment raise MaxRetryError(_pool, url, error or ResponseError(cause)) urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='kundenportal.berlin-recycling.de', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)'))) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/config/custom_components/waste_collection_schedule/waste_collection_schedule/scraper.py\", line 116, in fetch entries = self._source.fetch() File \"/config/custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py\", line 48, in fetch r = session.get(SERVICE_URL, allow_redirects=False) File \"/usr/local/lib/python3.9/site-packages/requests/sessions.py\", line 542, in get return self.request('GET', url, **kwargs) File \"/usr/local/lib/python3.9/site-packages/requests/sessions.py\", line 529, in request resp = self.send(prep, **send_kwargs) File \"/usr/local/lib/python3.9/site-packages/requests/sessions.py\", line 645, in send r = adapter.send(request, **kwargs) File \"/usr/local/lib/python3.9/site-packages/requests/adapters.py\", line 517, in send raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='kundenportal.berlin-recycling.de', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)')))\r\n\r\nSeems the reason is https://kundenportal.berlin-recycling.de has a misconfigured HTTPS server [which is not sending the intermediate certificate](https://www.ssllabs.com/ssltest/analyze.html?d=kundenportal.berlin-recycling.de) ([Starfield Secure Certificate Authority - G2](https://certs.starfieldtech.com/repository/)). Unlike browsers, python [does not support](https://bugs.python.org/issue18617) automatic fetching of missing intermediates.\r\n\r\nI think an option to avoid setting `verify = False` on the request would be pinning the CAs and shipping the certificates with the project.\n", "before_files": [{"content": "import json\nfrom datetime import datetime\nfrom html.parser import HTMLParser\n\nimport requests\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\n\nTITLE = \"Berline Recycling\"\nDESCRIPTION = \"Source for Berlin Recycling waste collection.\"\nURL = \"https://berlin-recycling.de\"\nTEST_CASES = {\n    \"Germanenstrasse\": {\n        \"username\": \"!secret berlin_recycling_username\",\n        \"password\": \"!secret berlin_recycling_password\",\n    },\n}\n\n\n# Parser for HTML input (hidden) text\nclass HiddenInputParser(HTMLParser):\n    def __init__(self):\n        super().__init__()\n        self._args = {}\n\n    @property\n    def args(self):\n        return self._args\n\n    def handle_starttag(self, tag, attrs):\n        if tag == \"input\":\n            d = dict(attrs)\n            if str(d[\"type\"]).lower() == \"hidden\":\n                self._args[d[\"name\"]] = d[\"value\"] if \"value\" in d else \"\"\n\n\nSERVICE_URL = \"https://kundenportal.berlin-recycling.de/\"\n\n\nclass Source:\n    def __init__(self, username, password):\n        self._username = username\n        self._password = password\n\n    def fetch(self):\n        session = requests.session()\n\n        # first get returns session specific url\n        r = session.get(SERVICE_URL, allow_redirects=False)\n\n        # get session id's\n        r = session.get(r.url)\n\n        parser = HiddenInputParser()\n        parser.feed(r.text)\n        args = parser.args\n        args[\"__EVENTTARGET\"] = \"btnLog\"\n        args[\"__EVENTARGUMENT\"] = None\n        args[\"Username\"] = self._username\n        args[\"Password\"] = self._password\n\n        # login\n        r = session.post(r.url, data=args)\n        serviceUrl = r.url\n\n        request_data = {\"withhtml\": \"true\"}\n        r = session.post(serviceUrl + \"/GetDashboard\", json=request_data)\n\n        request_data = {\"datasettable\": \"ENWIS_ABFUHRKALENDER\"}\n        r = session.post(serviceUrl + \"/ChangeDatasetTable\", json=request_data)\n\n        request_data = {\n            \"datasettablecode\": \"ENWIS_ABFUHRKALENDER\",\n            \"startindex\": 0,\n            \"searchtext\": \"\",\n            \"rangefilter\": \"\",\n            \"ordername\": \"\",\n            \"orderdir\": \"\",\n            \"ClientParameters\": \"\",\n            \"headrecid\": \"\",\n        }\n        r = session.post(serviceUrl + \"/GetDatasetTableHead\", json=request_data)\n\n        data = json.loads(r.text)\n        # load json again, because response is double coded\n        data = json.loads(data[\"d\"])\n\n        entries = []\n        for d in data[\"data\"]:\n            date = datetime.strptime(d[\"Task Date\"], \"%Y-%m-%d\").date()\n            entries.append(Collection(date, d[\"Material Description\"]))\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py"}], "after_files": [{"content": "import json\nfrom datetime import datetime\nfrom html.parser import HTMLParser\n\nimport requests\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\n\nTITLE = \"Berline Recycling\"\nDESCRIPTION = \"Source for Berlin Recycling waste collection.\"\nURL = \"https://berlin-recycling.de\"\nTEST_CASES = {\n    \"Germanenstrasse\": {\n        \"username\": \"!secret berlin_recycling_username\",\n        \"password\": \"!secret berlin_recycling_password\",\n    },\n}\n\n\n# Parser for HTML input (hidden) text\nclass HiddenInputParser(HTMLParser):\n    def __init__(self):\n        super().__init__()\n        self._args = {}\n\n    @property\n    def args(self):\n        return self._args\n\n    def handle_starttag(self, tag, attrs):\n        if tag == \"input\":\n            d = dict(attrs)\n            if str(d[\"type\"]).lower() == \"hidden\":\n                self._args[d[\"name\"]] = d[\"value\"] if \"value\" in d else \"\"\n\n\nSERVICE_URL = \"https://kundenportal.berlin-recycling.de/\"\n\n\nclass Source:\n    def __init__(self, username, password):\n        self._username = username\n        self._password = password\n\n    def fetch(self):\n        session = requests.session()\n\n        # first get returns session specific url\n        r = session.get(SERVICE_URL, allow_redirects=False, verify=False)\n\n        # get session id's\n        r = session.get(r.url)\n\n        parser = HiddenInputParser()\n        parser.feed(r.text)\n        args = parser.args\n        args[\"__EVENTTARGET\"] = \"btnLog\"\n        args[\"__EVENTARGUMENT\"] = None\n        args[\"Username\"] = self._username\n        args[\"Password\"] = self._password\n\n        # login\n        r = session.post(r.url, data=args)\n        serviceUrl = r.url\n\n        request_data = {\"withhtml\": \"true\"}\n        r = session.post(serviceUrl + \"/GetDashboard\", json=request_data)\n\n        request_data = {\"datasettable\": \"ENWIS_ABFUHRKALENDER\"}\n        r = session.post(serviceUrl + \"/ChangeDatasetTable\", json=request_data)\n\n        request_data = {\n            \"datasettablecode\": \"ENWIS_ABFUHRKALENDER\",\n            \"startindex\": 0,\n            \"searchtext\": \"\",\n            \"rangefilter\": \"\",\n            \"ordername\": \"\",\n            \"orderdir\": \"\",\n            \"ClientParameters\": \"\",\n            \"headrecid\": \"\",\n        }\n        r = session.post(serviceUrl + \"/GetDatasetTableHead\", json=request_data)\n\n        data = json.loads(r.text)\n        # load json again, because response is double coded\n        data = json.loads(data[\"d\"])\n\n        entries = []\n        for d in data[\"data\"]:\n            date = datetime.strptime(d[\"Task Date\"], \"%Y-%m-%d\").date()\n            entries.append(Collection(date, d[\"Material Description\"]))\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/berlin_recycling_de.py"}]}