src/eric7/EricNetwork/EricSslErrorHandler.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
23 23
24 class EricSslErrorState(enum.Enum): 24 class EricSslErrorState(enum.Enum):
25 """ 25 """
26 Class defining the SSL error handling states. 26 Class defining the SSL error handling states.
27 """ 27 """
28
28 NOT_IGNORED = 0 29 NOT_IGNORED = 0
29 SYSTEM_IGNORED = 1 30 SYSTEM_IGNORED = 1
30 USER_IGNORED = 2 31 USER_IGNORED = 2
31 32
32 33
33 class EricSslErrorHandler(QObject): 34 class EricSslErrorHandler(QObject):
34 """ 35 """
35 Class implementing a handler for SSL errors. 36 Class implementing a handler for SSL errors.
36 37
37 It also initializes the default SSL configuration with certificates 38 It also initializes the default SSL configuration with certificates
38 permanently accepted by the user already. 39 permanently accepted by the user already.
39 """ 40 """
41
40 def __init__(self, parent=None): 42 def __init__(self, parent=None):
41 """ 43 """
42 Constructor 44 Constructor
43 45
44 @param parent reference to the parent object (QObject) 46 @param parent reference to the parent object (QObject)
45 """ 47 """
46 super().__init__(parent) 48 super().__init__(parent)
47 49
48 caList = self.__getSystemCaCertificates() 50 caList = self.__getSystemCaCertificates()
49 if Preferences.getSettings().contains("Help/CaCertificatesDict"): 51 if Preferences.getSettings().contains("Help/CaCertificatesDict"):
50 # port old entries stored under 'Help' 52 # port old entries stored under 'Help'
51 certificateDict = Globals.toDict( 53 certificateDict = Globals.toDict(
52 Preferences.getSettings().value("Help/CaCertificatesDict")) 54 Preferences.getSettings().value("Help/CaCertificatesDict")
55 )
53 Preferences.getSettings().setValue( 56 Preferences.getSettings().setValue(
54 "Ssl/CaCertificatesDict", certificateDict) 57 "Ssl/CaCertificatesDict", certificateDict
58 )
55 Preferences.getSettings().remove("Help/CaCertificatesDict") 59 Preferences.getSettings().remove("Help/CaCertificatesDict")
56 else: 60 else:
57 certificateDict = Globals.toDict( 61 certificateDict = Globals.toDict(
58 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 62 Preferences.getSettings().value("Ssl/CaCertificatesDict")
63 )
59 for server in certificateDict: 64 for server in certificateDict:
60 for cert in QSslCertificate.fromData(certificateDict[server]): 65 for cert in QSslCertificate.fromData(certificateDict[server]):
61 if cert not in caList: 66 if cert not in caList:
62 caList.append(cert) 67 caList.append(cert)
63 sslCfg = QSslConfiguration.defaultConfiguration() 68 sslCfg = QSslConfiguration.defaultConfiguration()
64 sslCfg.setCaCertificates(caList) 69 sslCfg.setCaCertificates(caList)
65 try: 70 try:
66 sslProtocol = QSsl.SslProtocol.TlsV1_1OrLater 71 sslProtocol = QSsl.SslProtocol.TlsV1_1OrLater
67 if Globals.isWindowsPlatform() and platform.win32_ver()[0] == '7': 72 if Globals.isWindowsPlatform() and platform.win32_ver()[0] == "7":
68 sslProtocol = QSsl.SslProtocol.SecureProtocols 73 sslProtocol = QSsl.SslProtocol.SecureProtocols
69 except AttributeError: 74 except AttributeError:
70 sslProtocol = QSsl.SslProtocol.SecureProtocols 75 sslProtocol = QSsl.SslProtocol.SecureProtocols
71 sslCfg.setProtocol(sslProtocol) 76 sslCfg.setProtocol(sslProtocol)
72 with contextlib.suppress(AttributeError): 77 with contextlib.suppress(AttributeError):
73 sslCfg.setSslOption(QSsl.SslOption.SslOptionDisableCompression, 78 sslCfg.setSslOption(QSsl.SslOption.SslOptionDisableCompression, True)
74 True)
75 QSslConfiguration.setDefaultConfiguration(sslCfg) 79 QSslConfiguration.setDefaultConfiguration(sslCfg)
76 80
77 def sslErrorsReplySlot(self, reply, errors): 81 def sslErrorsReplySlot(self, reply, errors):
78 """ 82 """
79 Public slot to handle SSL errors for a network reply. 83 Public slot to handle SSL errors for a network reply.
80 84
81 @param reply reference to the reply object (QNetworkReply) 85 @param reply reference to the reply object (QNetworkReply)
82 @param errors list of SSL errors (list of QSslError) 86 @param errors list of SSL errors (list of QSslError)
83 """ 87 """
84 self.sslErrorsReply(reply, errors) 88 self.sslErrorsReply(reply, errors)
85 89
86 def sslErrorsReply(self, reply, errors): 90 def sslErrorsReply(self, reply, errors):
87 """ 91 """
88 Public slot to handle SSL errors for a network reply. 92 Public slot to handle SSL errors for a network reply.
89 93
90 @param reply reference to the reply object (QNetworkReply) 94 @param reply reference to the reply object (QNetworkReply)
91 @param errors list of SSL errors (list of QSslError) 95 @param errors list of SSL errors (list of QSslError)
92 @return tuple indicating to ignore the SSL errors (one of NotIgnored, 96 @return tuple indicating to ignore the SSL errors (one of NotIgnored,
93 SystemIgnored or UserIgnored) and indicating a change of the 97 SystemIgnored or UserIgnored) and indicating a change of the
94 default SSL configuration (boolean) 98 default SSL configuration (boolean)
95 """ 99 """
96 url = reply.url() 100 url = reply.url()
97 ignore, defaultChanged = self.sslErrors(errors, url.host(), url.port()) 101 ignore, defaultChanged = self.sslErrors(errors, url.host(), url.port())
98 if ignore: 102 if ignore:
99 if defaultChanged: 103 if defaultChanged:
100 reply.setSslConfiguration( 104 reply.setSslConfiguration(QSslConfiguration.defaultConfiguration())
101 QSslConfiguration.defaultConfiguration())
102 reply.ignoreSslErrors() 105 reply.ignoreSslErrors()
103 else: 106 else:
104 reply.abort() 107 reply.abort()
105 108
106 return ignore, defaultChanged 109 return ignore, defaultChanged
107 110
108 def sslErrors(self, errors, server, port=-1): 111 def sslErrors(self, errors, server, port=-1):
109 """ 112 """
110 Public method to handle SSL errors. 113 Public method to handle SSL errors.
111 114
112 @param errors list of SSL errors 115 @param errors list of SSL errors
113 @type list of QSslError 116 @type list of QSslError
114 @param server name of the server 117 @param server name of the server
115 @type str 118 @type str
116 @param port value of the port 119 @param port value of the port
119 change of the default SSL configuration 122 change of the default SSL configuration
120 @rtype tuple of (EricSslErrorState, bool) 123 @rtype tuple of (EricSslErrorState, bool)
121 """ 124 """
122 caMerge = {} 125 caMerge = {}
123 certificateDict = Globals.toDict( 126 certificateDict = Globals.toDict(
124 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 127 Preferences.getSettings().value("Ssl/CaCertificatesDict")
128 )
125 for caServer in certificateDict: 129 for caServer in certificateDict:
126 caMerge[caServer] = QSslCertificate.fromData( 130 caMerge[caServer] = QSslCertificate.fromData(certificateDict[caServer])
127 certificateDict[caServer])
128 caNew = [] 131 caNew = []
129 132
130 errorStrings = [] 133 errorStrings = []
131 if port != -1: 134 if port != -1:
132 server += ":{0:d}".format(port) 135 server += ":{0:d}".format(port)
133 if errors: 136 if errors:
134 for err in errors: 137 for err in errors:
141 cert = err.certificate() 144 cert = err.certificate()
142 if cert not in caNew: 145 if cert not in caNew:
143 caNew.append(cert) 146 caNew.append(cert)
144 if not errorStrings: 147 if not errorStrings:
145 return EricSslErrorState.SYSTEM_IGNORED, False 148 return EricSslErrorState.SYSTEM_IGNORED, False
146 149
147 errorString = '.</li><li>'.join(errorStrings) 150 errorString = ".</li><li>".join(errorStrings)
148 ret = EricMessageBox.yesNo( 151 ret = EricMessageBox.yesNo(
149 None, 152 None,
150 self.tr("SSL Errors"), 153 self.tr("SSL Errors"),
151 self.tr("""<p>SSL Errors for <br /><b>{0}</b>""" 154 self.tr(
152 """<ul><li>{1}</li></ul></p>""" 155 """<p>SSL Errors for <br /><b>{0}</b>"""
153 """<p>Do you want to ignore these errors?</p>""") 156 """<ul><li>{1}</li></ul></p>"""
154 .format(server, errorString), 157 """<p>Do you want to ignore these errors?</p>"""
155 icon=EricMessageBox.Warning) 158 ).format(server, errorString),
156 159 icon=EricMessageBox.Warning,
160 )
161
157 if ret: 162 if ret:
158 caRet = False 163 caRet = False
159 if len(caNew) > 0: 164 if len(caNew) > 0:
160 certinfos = [] 165 certinfos = []
161 for cert in caNew: 166 for cert in caNew:
164 None, 169 None,
165 self.tr("Certificates"), 170 self.tr("Certificates"),
166 self.tr( 171 self.tr(
167 """<p>Certificates:<br/>{0}<br/>""" 172 """<p>Certificates:<br/>{0}<br/>"""
168 """Do you want to accept all these certificates?""" 173 """Do you want to accept all these certificates?"""
169 """</p>""") 174 """</p>"""
170 .format("".join(certinfos))) 175 ).format("".join(certinfos)),
176 )
171 if caRet: 177 if caRet:
172 if server not in caMerge: 178 if server not in caMerge:
173 caMerge[server] = [] 179 caMerge[server] = []
174 for cert in caNew: 180 for cert in caNew:
175 caMerge[server].append(cert) 181 caMerge[server].append(cert)
176 182
177 sslCfg = QSslConfiguration.defaultConfiguration() 183 sslCfg = QSslConfiguration.defaultConfiguration()
178 caList = sslCfg.caCertificates() 184 caList = sslCfg.caCertificates()
179 for cert in caNew: 185 for cert in caNew:
180 caList.append(cert) 186 caList.append(cert)
181 sslCfg.setCaCertificates(caList) 187 sslCfg.setCaCertificates(caList)
183 sslCfg.setProtocol(QSsl.SslProtocol.TlsV1_1OrLater) 189 sslCfg.setProtocol(QSsl.SslProtocol.TlsV1_1OrLater)
184 except AttributeError: 190 except AttributeError:
185 sslCfg.setProtocol(QSsl.SslProtocol.SecureProtocols) 191 sslCfg.setProtocol(QSsl.SslProtocol.SecureProtocols)
186 with contextlib.suppress(AttributeError): 192 with contextlib.suppress(AttributeError):
187 sslCfg.setSslOption( 193 sslCfg.setSslOption(
188 QSsl.SslOption.SslOptionDisableCompression, 194 QSsl.SslOption.SslOptionDisableCompression, True
189 True) 195 )
190 QSslConfiguration.setDefaultConfiguration(sslCfg) 196 QSslConfiguration.setDefaultConfiguration(sslCfg)
191 197
192 certificateDict = {} 198 certificateDict = {}
193 for server in caMerge: 199 for server in caMerge:
194 pems = QByteArray() 200 pems = QByteArray()
195 for cert in caMerge[server]: 201 for cert in caMerge[server]:
196 pems.append(cert.toPem() + b'\n') 202 pems.append(cert.toPem() + b"\n")
197 certificateDict[server] = pems 203 certificateDict[server] = pems
198 Preferences.getSettings().setValue( 204 Preferences.getSettings().setValue(
199 "Ssl/CaCertificatesDict", 205 "Ssl/CaCertificatesDict", certificateDict
200 certificateDict) 206 )
201 207
202 return EricSslErrorState.USER_IGNORED, caRet 208 return EricSslErrorState.USER_IGNORED, caRet
203 209
204 else: 210 else:
205 return EricSslErrorState.NOT_IGNORED, False 211 return EricSslErrorState.NOT_IGNORED, False
206 212
207 def __certToString(self, cert): 213 def __certToString(self, cert):
208 """ 214 """
209 Private method to convert a certificate to a formatted string. 215 Private method to convert a certificate to a formatted string.
210 216
211 @param cert certificate to convert (QSslCertificate) 217 @param cert certificate to convert (QSslCertificate)
212 @return formatted string (string) 218 @return formatted string (string)
213 """ 219 """
214 result = "<p>" 220 result = "<p>"
215 221
216 result += self.tr( 222 result += self.tr("Name: {0}").format(
217 "Name: {0}"
218 ).format(
219 Utilities.html_encode( 223 Utilities.html_encode(
220 Utilities.decodeString( 224 Utilities.decodeString(
221 ", ".join(cert.subjectInfo( 225 ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName))
222 QSslCertificate.SubjectInfo.CommonName)) 226 )
223 ) 227 )
224 ) 228 )
225 ) 229
226 230 result += self.tr("<br/>Organization: {0}").format(
227 result += self.tr(
228 "<br/>Organization: {0}"
229 ).format(
230 Utilities.html_encode( 231 Utilities.html_encode(
231 Utilities.decodeString( 232 Utilities.decodeString(
232 ", ".join(cert.subjectInfo( 233 ", ".join(
233 QSslCertificate.SubjectInfo.Organization)) 234 cert.subjectInfo(QSslCertificate.SubjectInfo.Organization)
234 ) 235 )
235 ) 236 )
236 ) 237 )
237 238 )
238 result += self.tr( 239
239 "<br/>Issuer: {0}" 240 result += self.tr("<br/>Issuer: {0}").format(
240 ).format(
241 Utilities.html_encode( 241 Utilities.html_encode(
242 Utilities.decodeString( 242 Utilities.decodeString(
243 ", ".join(cert.issuerInfo( 243 ", ".join(cert.issuerInfo(QSslCertificate.SubjectInfo.CommonName))
244 QSslCertificate.SubjectInfo.CommonName)) 244 )
245 ) 245 )
246 ) 246 )
247 ) 247 result += self.tr("<br/>Not valid before: {0}<br/>Valid Until: {1}").format(
248 result += self.tr( 248 Utilities.html_encode(cert.effectiveDate().toString("yyyy-MM-dd")),
249 "<br/>Not valid before: {0}<br/>Valid Until: {1}" 249 Utilities.html_encode(cert.expiryDate().toString("yyyy-MM-dd")),
250 ).format( 250 )
251 Utilities.html_encode( 251
252 cert.effectiveDate().toString("yyyy-MM-dd")
253 ),
254 Utilities.html_encode(
255 cert.expiryDate().toString("yyyy-MM-dd")
256 )
257 )
258
259 result += "</p>" 252 result += "</p>"
260 253
261 return result 254 return result
262 255
263 def __getSystemCaCertificates(self): 256 def __getSystemCaCertificates(self):
264 """ 257 """
265 Private method to get the list of system certificates. 258 Private method to get the list of system certificates.
266 259
267 @return list of system certificates (list of QSslCertificate) 260 @return list of system certificates (list of QSslCertificate)
268 """ 261 """
269 caList = QSslCertificate.fromData(Globals.toByteArray( 262 caList = QSslCertificate.fromData(
270 Preferences.getSettings().value("Ssl/SystemCertificates"))) 263 Globals.toByteArray(
264 Preferences.getSettings().value("Ssl/SystemCertificates")
265 )
266 )
271 if not caList: 267 if not caList:
272 caList = QSslConfiguration.systemCaCertificates() 268 caList = QSslConfiguration.systemCaCertificates()
273 return caList 269 return caList

eric ide

mercurial