5 |
5 |
6 """ |
6 """ |
7 Module implementing a SSL error handler. |
7 Module implementing a SSL error handler. |
8 """ |
8 """ |
9 |
9 |
|
10 import contextlib |
|
11 import enum |
10 import platform |
12 import platform |
11 |
13 |
12 from PyQt5.QtCore import QObject, QByteArray |
14 from PyQt5.QtCore import QObject, QByteArray |
13 from PyQt5.QtNetwork import ( |
15 from PyQt5.QtNetwork import ( |
14 QSslCertificate, QSslConfiguration, QSslSocket, QSslError, QSsl |
16 QSslCertificate, QSslConfiguration, QSslSocket, QSslError, QSsl |
19 import Preferences |
21 import Preferences |
20 import Utilities |
22 import Utilities |
21 import Globals |
23 import Globals |
22 |
24 |
23 |
25 |
|
26 class E5SslErrorState(enum.Enum): |
|
27 """ |
|
28 Class defining the SSL error handling states. |
|
29 """ |
|
30 NOT_IGNORED = 0 |
|
31 SYSTEM_IGNORED = 1 |
|
32 USER_IGNORED = 2 |
|
33 |
|
34 |
24 class E5SslErrorHandler(QObject): |
35 class E5SslErrorHandler(QObject): |
25 """ |
36 """ |
26 Class implementing a handler for SSL errors. |
37 Class implementing a handler for SSL errors. |
27 |
38 |
28 It also initializes the default SSL configuration with certificates |
39 It also initializes the default SSL configuration with certificates |
29 permanently accepted by the user already. |
40 permanently accepted by the user already. |
30 """ |
41 """ |
31 NotIgnored = 0 |
|
32 SystemIgnored = 1 |
|
33 UserIgnored = 2 |
|
34 |
|
35 def __init__(self, parent=None): |
42 def __init__(self, parent=None): |
36 """ |
43 """ |
37 Constructor |
44 Constructor |
38 |
45 |
39 @param parent reference to the parent object (QObject) |
46 @param parent reference to the parent object (QObject) |
40 """ |
47 """ |
41 super(E5SslErrorHandler, self).__init__(parent) |
48 super().__init__(parent) |
42 |
49 |
43 caList = self.__getSystemCaCertificates() |
50 caList = self.__getSystemCaCertificates() |
44 if Preferences.Prefs.settings.contains("Help/CaCertificatesDict"): |
51 if Preferences.Prefs.settings.contains("Help/CaCertificatesDict"): |
45 # port old entries stored under 'Help' |
52 # port old entries stored under 'Help' |
46 certificateDict = Globals.toDict( |
53 certificateDict = Globals.toDict( |
62 if Globals.isWindowsPlatform() and platform.win32_ver()[0] == '7': |
69 if Globals.isWindowsPlatform() and platform.win32_ver()[0] == '7': |
63 sslProtocol = QSsl.SslProtocol.SecureProtocols |
70 sslProtocol = QSsl.SslProtocol.SecureProtocols |
64 except AttributeError: |
71 except AttributeError: |
65 sslProtocol = QSsl.SslProtocol.SecureProtocols |
72 sslProtocol = QSsl.SslProtocol.SecureProtocols |
66 sslCfg.setProtocol(sslProtocol) |
73 sslCfg.setProtocol(sslProtocol) |
67 try: |
74 with contextlib.suppress(AttributeError): |
68 sslCfg.setSslOption(QSsl.SslOption.SslOptionDisableCompression, |
75 sslCfg.setSslOption(QSsl.SslOption.SslOptionDisableCompression, |
69 True) |
76 True) |
70 except AttributeError: |
|
71 pass |
|
72 QSslConfiguration.setDefaultConfiguration(sslCfg) |
77 QSslConfiguration.setDefaultConfiguration(sslCfg) |
73 |
78 |
74 def sslErrorsReplySlot(self, reply, errors): |
79 def sslErrorsReplySlot(self, reply, errors): |
75 """ |
80 """ |
76 Public slot to handle SSL errors for a network reply. |
81 Public slot to handle SSL errors for a network reply. |
104 |
109 |
105 def sslErrors(self, errors, server, port=-1): |
110 def sslErrors(self, errors, server, port=-1): |
106 """ |
111 """ |
107 Public method to handle SSL errors. |
112 Public method to handle SSL errors. |
108 |
113 |
109 @param errors list of SSL errors (list of QSslError) |
114 @param errors list of SSL errors |
110 @param server name of the server (string) |
115 @type list of QSslError |
111 @param port value of the port (integer) |
116 @param server name of the server |
112 @return tuple indicating to ignore the SSL errors (one of NotIgnored, |
117 @type str |
113 SystemIgnored or UserIgnored) and indicating a change of the |
118 @param port value of the port |
114 default SSL configuration (boolean) |
119 @type int |
|
120 @return tuple indicating to ignore the SSL errors and indicating a |
|
121 change of the default SSL configuration |
|
122 @rtype tuple of (E5SslErrorState, bool) |
115 """ |
123 """ |
116 caMerge = {} |
124 caMerge = {} |
117 certificateDict = Globals.toDict( |
125 certificateDict = Globals.toDict( |
118 Preferences.Prefs.settings.value("Ssl/CaCertificatesDict")) |
126 Preferences.Prefs.settings.value("Ssl/CaCertificatesDict")) |
119 for caServer in certificateDict: |
127 for caServer in certificateDict: |
134 if not err.certificate().isNull(): |
142 if not err.certificate().isNull(): |
135 cert = err.certificate() |
143 cert = err.certificate() |
136 if cert not in caNew: |
144 if cert not in caNew: |
137 caNew.append(cert) |
145 caNew.append(cert) |
138 if not errorStrings: |
146 if not errorStrings: |
139 return E5SslErrorHandler.SystemIgnored, False |
147 return E5SslErrorState.SYSTEM_IGNORED, False |
140 |
148 |
141 errorString = '.</li><li>'.join(errorStrings) |
149 errorString = '.</li><li>'.join(errorStrings) |
142 ret = E5MessageBox.yesNo( |
150 ret = E5MessageBox.yesNo( |
143 None, |
151 None, |
144 self.tr("SSL Errors"), |
152 self.tr("SSL Errors"), |
175 sslCfg.setCaCertificates(caList) |
183 sslCfg.setCaCertificates(caList) |
176 try: |
184 try: |
177 sslCfg.setProtocol(QSsl.SslProtocol.TlsV1_1OrLater) |
185 sslCfg.setProtocol(QSsl.SslProtocol.TlsV1_1OrLater) |
178 except AttributeError: |
186 except AttributeError: |
179 sslCfg.setProtocol(QSsl.SslProtocol.SecureProtocols) |
187 sslCfg.setProtocol(QSsl.SslProtocol.SecureProtocols) |
180 try: |
188 with contextlib.suppress(AttributeError): |
181 sslCfg.setSslOption( |
189 sslCfg.setSslOption( |
182 QSsl.SslOption.SslOptionDisableCompression, |
190 QSsl.SslOption.SslOptionDisableCompression, |
183 True) |
191 True) |
184 except AttributeError: |
|
185 pass |
|
186 QSslConfiguration.setDefaultConfiguration(sslCfg) |
192 QSslConfiguration.setDefaultConfiguration(sslCfg) |
187 |
193 |
188 certificateDict = {} |
194 certificateDict = {} |
189 for server in caMerge: |
195 for server in caMerge: |
190 pems = QByteArray() |
196 pems = QByteArray() |
193 certificateDict[server] = pems |
199 certificateDict[server] = pems |
194 Preferences.Prefs.settings.setValue( |
200 Preferences.Prefs.settings.setValue( |
195 "Ssl/CaCertificatesDict", |
201 "Ssl/CaCertificatesDict", |
196 certificateDict) |
202 certificateDict) |
197 |
203 |
198 return E5SslErrorHandler.UserIgnored, caRet |
204 return E5SslErrorState.USER_IGNORED, caRet |
199 |
205 |
200 else: |
206 else: |
201 return E5SslErrorHandler.NotIgnored, False |
207 return E5SslErrorState.NOT_IGNORED, False |
202 |
208 |
203 def __certToString(self, cert): |
209 def __certToString(self, cert): |
204 """ |
210 """ |
205 Private method to convert a certificate to a formatted string. |
211 Private method to convert a certificate to a formatted string. |
206 |
212 |