|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2008 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 |
|
7 """ |
|
8 Module implementing the helpbrowser using QWebView. |
|
9 """ |
|
10 |
|
11 from PyQt5.QtCore import ( |
|
12 pyqtSlot, pyqtSignal, QUrl, QUrlQuery, QTimer, QEventLoop, QPoint, QPointF, |
|
13 QT_VERSION |
|
14 ) |
|
15 from PyQt5.QtGui import QDesktopServices |
|
16 from PyQt5.QtWebEngineWidgets import ( |
|
17 QWebEnginePage, QWebEngineSettings, QWebEngineScript |
|
18 ) |
|
19 try: |
|
20 from PyQt5.QtWebEngine import PYQT_WEBENGINE_VERSION |
|
21 # __IGNORE_EXCEPTION__ |
|
22 except (AttributeError, ImportError): |
|
23 PYQT_WEBENGINE_VERSION = QT_VERSION |
|
24 from PyQt5.QtWebChannel import QWebChannel |
|
25 |
|
26 try: |
|
27 from PyQt5.QtNetwork import QSslConfiguration, QSslCertificate |
|
28 SSL_AVAILABLE = True |
|
29 except ImportError: |
|
30 SSL_AVAILABLE = False |
|
31 |
|
32 from E5Gui import E5MessageBox |
|
33 |
|
34 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
35 |
|
36 from .JavaScript.ExternalJsObject import ExternalJsObject |
|
37 |
|
38 from .Tools.WebHitTestResult import WebHitTestResult |
|
39 from .Tools import Scripts |
|
40 |
|
41 import Preferences |
|
42 import Globals |
|
43 |
|
44 |
|
45 class WebBrowserPage(QWebEnginePage): |
|
46 """ |
|
47 Class implementing an enhanced web page. |
|
48 |
|
49 @signal safeBrowsingAbort() emitted to indicate an abort due to a safe |
|
50 browsing event |
|
51 @signal safeBrowsingBad(threatType, threatMessages) emitted to indicate a |
|
52 malicious web site as determined by safe browsing |
|
53 @signal printPageRequested() emitted to indicate a print request of the |
|
54 shown web page |
|
55 @signal navigationRequestAccepted(url, navigation type, main frame) emitted |
|
56 to signal an accepted navigation request |
|
57 @signal sslConfigurationChanged() emitted to indicate a change of the |
|
58 stored SSL configuration data |
|
59 """ |
|
60 SafeJsWorld = QWebEngineScript.ScriptWorldId.ApplicationWorld |
|
61 UnsafeJsWorld = QWebEngineScript.ScriptWorldId.MainWorld |
|
62 |
|
63 safeBrowsingAbort = pyqtSignal() |
|
64 safeBrowsingBad = pyqtSignal(str, str) |
|
65 |
|
66 printPageRequested = pyqtSignal() |
|
67 navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType, |
|
68 bool) |
|
69 |
|
70 sslConfigurationChanged = pyqtSignal() |
|
71 |
|
72 def __init__(self, parent=None): |
|
73 """ |
|
74 Constructor |
|
75 |
|
76 @param parent parent widget of this window (QWidget) |
|
77 """ |
|
78 super().__init__( |
|
79 WebBrowserWindow.webProfile(), parent) |
|
80 |
|
81 self.__printer = None |
|
82 self.__badSite = False |
|
83 self.__registerProtocolHandlerRequest = None |
|
84 |
|
85 self.featurePermissionRequested.connect( |
|
86 self.__featurePermissionRequested) |
|
87 self.authenticationRequired.connect( |
|
88 lambda url, auth: WebBrowserWindow.networkManager().authentication( |
|
89 url, auth, self)) |
|
90 self.proxyAuthenticationRequired.connect( |
|
91 WebBrowserWindow.networkManager().proxyAuthentication) |
|
92 self.fullScreenRequested.connect(self.__fullScreenRequested) |
|
93 self.urlChanged.connect(self.__urlChanged) |
|
94 self.contentsSizeChanged.connect(self.__contentsSizeChanged) |
|
95 self.registerProtocolHandlerRequested.connect( |
|
96 self.__registerProtocolHandlerRequested) |
|
97 |
|
98 self.__sslConfiguration = None |
|
99 |
|
100 # Workaround for changing webchannel world inside |
|
101 # acceptNavigationRequest not working |
|
102 self.__channelUrl = QUrl() |
|
103 self.__channelWorldId = -1 |
|
104 self.__setupChannelTimer = QTimer(self) |
|
105 self.__setupChannelTimer.setSingleShot(True) |
|
106 self.__setupChannelTimer.setInterval(100) |
|
107 self.__setupChannelTimer.timeout.connect(self.__setupChannelTimeout) |
|
108 |
|
109 @pyqtSlot() |
|
110 def __setupChannelTimeout(self): |
|
111 """ |
|
112 Private slot to initiate the setup of the web channel. |
|
113 """ |
|
114 self.__setupWebChannelForUrl(self.__channelUrl) |
|
115 |
|
116 def acceptNavigationRequest(self, url, type_, isMainFrame): |
|
117 """ |
|
118 Public method to determine, if a request may be accepted. |
|
119 |
|
120 @param url URL to navigate to |
|
121 @type QUrl |
|
122 @param type_ type of the navigation request |
|
123 @type QWebEnginePage.NavigationType |
|
124 @param isMainFrame flag indicating, that the request originated from |
|
125 the main frame |
|
126 @type bool |
|
127 @return flag indicating acceptance |
|
128 @rtype bool |
|
129 """ |
|
130 scheme = url.scheme() |
|
131 if scheme == "mailto": |
|
132 QDesktopServices.openUrl(url) |
|
133 return False |
|
134 |
|
135 # AdBlock |
|
136 if ( |
|
137 url.scheme() == "abp" and |
|
138 WebBrowserWindow.adBlockManager().addSubscriptionFromUrl(url) |
|
139 ): |
|
140 return False |
|
141 |
|
142 # GreaseMonkey |
|
143 try: |
|
144 # PyQtWebEngine >= 5.14.0 |
|
145 navigationType = type_ in [ |
|
146 QWebEnginePage.NavigationType.NavigationTypeLinkClicked, |
|
147 QWebEnginePage.NavigationType.NavigationTypeRedirect |
|
148 ] |
|
149 except AttributeError: |
|
150 navigationType = ( |
|
151 type_ == |
|
152 QWebEnginePage.NavigationType.NavigationTypeLinkClicked |
|
153 ) |
|
154 if navigationType and url.toString().endswith(".user.js"): |
|
155 WebBrowserWindow.greaseMonkeyManager().downloadScript(url) |
|
156 return False |
|
157 |
|
158 if url.scheme() == "eric": |
|
159 if url.path() == "AddSearchProvider": |
|
160 query = QUrlQuery(url) |
|
161 self.view().mainWindow().openSearchManager().addEngine( |
|
162 QUrl(query.queryItemValue("url"))) |
|
163 return False |
|
164 elif url.path() == "PrintPage": |
|
165 self.printPageRequested.emit() |
|
166 return False |
|
167 |
|
168 # Safe Browsing |
|
169 self.__badSite = False |
|
170 from WebBrowser.SafeBrowsing.SafeBrowsingManager import ( |
|
171 SafeBrowsingManager |
|
172 ) |
|
173 if ( |
|
174 SafeBrowsingManager.isEnabled() and |
|
175 url.scheme() not in SafeBrowsingManager.getIgnoreSchemes() |
|
176 ): |
|
177 threatLists = ( |
|
178 WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0] |
|
179 ) |
|
180 if threatLists: |
|
181 threatMessages = ( |
|
182 WebBrowserWindow.safeBrowsingManager() |
|
183 .getThreatMessages(threatLists) |
|
184 ) |
|
185 res = E5MessageBox.warning( |
|
186 WebBrowserWindow.getWindow(), |
|
187 self.tr("Suspicuous URL detected"), |
|
188 self.tr("<p>The URL <b>{0}</b> was found in the Safe" |
|
189 " Browsing database.</p>{1}").format( |
|
190 url.toString(), "".join(threatMessages)), |
|
191 E5MessageBox.StandardButtons( |
|
192 E5MessageBox.Abort | |
|
193 E5MessageBox.Ignore), |
|
194 E5MessageBox.Abort) |
|
195 if res == E5MessageBox.Abort: |
|
196 self.safeBrowsingAbort.emit() |
|
197 return False |
|
198 |
|
199 self.__badSite = True |
|
200 threatType = ( |
|
201 WebBrowserWindow.safeBrowsingManager() |
|
202 .getThreatType(threatLists[0]) |
|
203 ) |
|
204 self.safeBrowsingBad.emit(threatType, "".join(threatMessages)) |
|
205 |
|
206 result = QWebEnginePage.acceptNavigationRequest( |
|
207 self, url, type_, isMainFrame) |
|
208 |
|
209 if result: |
|
210 if isMainFrame: |
|
211 isWeb = url.scheme() in ("http", "https", "ftp", "ftps", |
|
212 "file") |
|
213 globalJsEnabled = WebBrowserWindow.webSettings().testAttribute( |
|
214 QWebEngineSettings.WebAttribute.JavascriptEnabled) |
|
215 if isWeb: |
|
216 enable = globalJsEnabled |
|
217 else: |
|
218 enable = True |
|
219 self.settings().setAttribute( |
|
220 QWebEngineSettings.WebAttribute.JavascriptEnabled, enable) |
|
221 |
|
222 self.__channelUrl = url |
|
223 self.__setupChannelTimer.start() |
|
224 self.navigationRequestAccepted.emit(url, type_, isMainFrame) |
|
225 |
|
226 return result |
|
227 |
|
228 @pyqtSlot(QUrl) |
|
229 def __urlChanged(self, url): |
|
230 """ |
|
231 Private slot to handle changes of the URL. |
|
232 |
|
233 @param url new URL |
|
234 @type QUrl |
|
235 """ |
|
236 if ( |
|
237 not url.isEmpty() and |
|
238 url.scheme() == "eric" and |
|
239 not self.isJavaScriptEnabled() |
|
240 ): |
|
241 self.settings().setAttribute( |
|
242 QWebEngineSettings.WebAttribute.JavascriptEnabled, True) |
|
243 self.triggerAction(QWebEnginePage.WebAction.Reload) |
|
244 |
|
245 @classmethod |
|
246 def userAgent(cls, resolveEmpty=False): |
|
247 """ |
|
248 Class method to get the global user agent setting. |
|
249 |
|
250 @param resolveEmpty flag indicating to resolve an empty |
|
251 user agent (boolean) |
|
252 @return user agent string (string) |
|
253 """ |
|
254 agent = Preferences.getWebBrowser("UserAgent") |
|
255 if agent == "" and resolveEmpty: |
|
256 agent = cls.userAgentForUrl(QUrl()) |
|
257 return agent |
|
258 |
|
259 @classmethod |
|
260 def setUserAgent(cls, agent): |
|
261 """ |
|
262 Class method to set the global user agent string. |
|
263 |
|
264 @param agent new current user agent string (string) |
|
265 """ |
|
266 Preferences.setWebBrowser("UserAgent", agent) |
|
267 |
|
268 @classmethod |
|
269 def userAgentForUrl(cls, url): |
|
270 """ |
|
271 Class method to determine the user agent for the given URL. |
|
272 |
|
273 @param url URL to determine user agent for (QUrl) |
|
274 @return user agent string (string) |
|
275 """ |
|
276 agent = WebBrowserWindow.userAgentsManager().userAgentForUrl(url) |
|
277 if agent == "": |
|
278 # no agent string specified for the given host -> use global one |
|
279 agent = Preferences.getWebBrowser("UserAgent") |
|
280 if agent == "": |
|
281 # no global agent string specified -> use default one |
|
282 agent = WebBrowserWindow.webProfile().httpUserAgent() |
|
283 return agent |
|
284 |
|
285 def __featurePermissionRequested(self, url, feature): |
|
286 """ |
|
287 Private slot handling a feature permission request. |
|
288 |
|
289 @param url url requesting the feature |
|
290 @type QUrl |
|
291 @param feature requested feature |
|
292 @type QWebEnginePage.Feature |
|
293 """ |
|
294 manager = WebBrowserWindow.featurePermissionManager() |
|
295 manager.requestFeaturePermission(self, url, feature) |
|
296 |
|
297 def execJavaScript(self, script, |
|
298 worldId=QWebEngineScript.ScriptWorldId.MainWorld, |
|
299 timeout=500): |
|
300 """ |
|
301 Public method to execute a JavaScript function synchroneously. |
|
302 |
|
303 @param script JavaScript script source to be executed |
|
304 @type str |
|
305 @param worldId ID to run the script under |
|
306 @type QWebEngineScript.ScriptWorldId |
|
307 @param timeout max. time the script is given to execute |
|
308 @type int |
|
309 @return result of the script |
|
310 @rtype depending upon script result |
|
311 """ |
|
312 loop = QEventLoop() |
|
313 resultDict = {"res": None} |
|
314 QTimer.singleShot(timeout, loop.quit) |
|
315 |
|
316 def resultCallback(res, resDict=resultDict): |
|
317 if loop and loop.isRunning(): |
|
318 resDict["res"] = res |
|
319 loop.quit() |
|
320 |
|
321 self.runJavaScript(script, worldId, resultCallback) |
|
322 |
|
323 loop.exec() |
|
324 return resultDict["res"] |
|
325 |
|
326 def runJavaScript(self, script, worldId=-1, callback=None): |
|
327 """ |
|
328 Public method to run a script in the context of the page. |
|
329 |
|
330 @param script JavaScript script source to be executed |
|
331 @type str |
|
332 @param worldId ID to run the script under |
|
333 @type int |
|
334 @param callback callback function to be executed when the script has |
|
335 ended |
|
336 @type function |
|
337 """ |
|
338 if worldId > -1: |
|
339 if callback is None: |
|
340 QWebEnginePage.runJavaScript(self, script, worldId) |
|
341 else: |
|
342 QWebEnginePage.runJavaScript(self, script, worldId, callback) |
|
343 else: |
|
344 if callback is None: |
|
345 QWebEnginePage.runJavaScript(self, script) |
|
346 else: |
|
347 QWebEnginePage.runJavaScript(self, script, callback) |
|
348 |
|
349 def isJavaScriptEnabled(self): |
|
350 """ |
|
351 Public method to test, if JavaScript is enabled. |
|
352 |
|
353 @return flag indicating the state of the JavaScript support |
|
354 @rtype bool |
|
355 """ |
|
356 return self.settings().testAttribute( |
|
357 QWebEngineSettings.WebAttribute.JavascriptEnabled) |
|
358 |
|
359 def scroll(self, x, y): |
|
360 """ |
|
361 Public method to scroll by the given amount of pixels. |
|
362 |
|
363 @param x horizontal scroll value |
|
364 @type int |
|
365 @param y vertical scroll value |
|
366 @type int |
|
367 """ |
|
368 self.runJavaScript( |
|
369 "window.scrollTo(window.scrollX + {0}, window.scrollY + {1})" |
|
370 .format(x, y), |
|
371 WebBrowserPage.SafeJsWorld |
|
372 ) |
|
373 |
|
374 def scrollTo(self, pos): |
|
375 """ |
|
376 Public method to scroll to the given position. |
|
377 |
|
378 @param pos position to scroll to |
|
379 @type QPointF |
|
380 """ |
|
381 self.runJavaScript( |
|
382 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()), |
|
383 WebBrowserPage.SafeJsWorld |
|
384 ) |
|
385 |
|
386 def mapToViewport(self, pos): |
|
387 """ |
|
388 Public method to map a position to the viewport. |
|
389 |
|
390 @param pos position to be mapped |
|
391 @type QPoint |
|
392 @return viewport position |
|
393 @rtype QPoint |
|
394 """ |
|
395 return QPoint(pos.x() // self.zoomFactor(), |
|
396 pos.y() // self.zoomFactor()) |
|
397 |
|
398 def hitTestContent(self, pos): |
|
399 """ |
|
400 Public method to test the content at a specified position. |
|
401 |
|
402 @param pos position to execute the test at |
|
403 @type QPoint |
|
404 @return test result object |
|
405 @rtype WebHitTestResult |
|
406 """ |
|
407 return WebHitTestResult(self, pos) |
|
408 |
|
409 def __setupWebChannelForUrl(self, url): |
|
410 """ |
|
411 Private method to setup a web channel to our external object. |
|
412 |
|
413 @param url URL for which to setup the web channel |
|
414 @type QUrl |
|
415 """ |
|
416 channel = self.webChannel() |
|
417 if channel is None: |
|
418 channel = QWebChannel(self) |
|
419 ExternalJsObject.setupWebChannel(channel, self) |
|
420 |
|
421 worldId = -1 |
|
422 worldId = ( |
|
423 self.UnsafeJsWorld |
|
424 if url.scheme() in ("eric", "qthelp") else |
|
425 self.SafeJsWorld |
|
426 ) |
|
427 if worldId != self.__channelWorldId: |
|
428 self.__channelWorldId = worldId |
|
429 try: |
|
430 self.setWebChannel(channel, self.__channelWorldId) |
|
431 except TypeError: |
|
432 # pre Qt 5.7.0 |
|
433 self.setWebChannel(channel) |
|
434 |
|
435 def certificateError(self, error): |
|
436 """ |
|
437 Public method to handle SSL certificate errors. |
|
438 |
|
439 @param error object containing the certificate error information |
|
440 @type QWebEngineCertificateError |
|
441 @return flag indicating to ignore this error |
|
442 @rtype bool |
|
443 """ |
|
444 return WebBrowserWindow.networkManager().certificateError( |
|
445 error, self.view()) |
|
446 |
|
447 def __fullScreenRequested(self, request): |
|
448 """ |
|
449 Private slot handling a full screen request. |
|
450 |
|
451 @param request reference to the full screen request |
|
452 @type QWebEngineFullScreenRequest |
|
453 """ |
|
454 self.view().requestFullScreen(request.toggleOn()) |
|
455 |
|
456 accepted = request.toggleOn() == self.view().isFullScreen() |
|
457 |
|
458 if accepted: |
|
459 request.accept() |
|
460 else: |
|
461 request.reject() |
|
462 |
|
463 def execPrintPage(self, printer, timeout=1000): |
|
464 """ |
|
465 Public method to execute a synchronous print. |
|
466 |
|
467 @param printer reference to the printer object |
|
468 @type QPrinter |
|
469 @param timeout timeout value in milliseconds |
|
470 @type int |
|
471 @return flag indicating a successful print job |
|
472 @rtype bool |
|
473 """ |
|
474 loop = QEventLoop() |
|
475 resultDict = {"res": None} |
|
476 QTimer.singleShot(timeout, loop.quit) |
|
477 |
|
478 def printCallback(res, resDict=resultDict): |
|
479 if loop and loop.isRunning(): |
|
480 resDict["res"] = res |
|
481 loop.quit() |
|
482 |
|
483 self.print(printer, printCallback) |
|
484 |
|
485 loop.exec() |
|
486 return resultDict["res"] |
|
487 |
|
488 def __contentsSizeChanged(self, size): |
|
489 """ |
|
490 Private slot to work around QWebEnginePage not scrolling to anchors |
|
491 when opened in a background tab. |
|
492 |
|
493 @param size changed contents size (unused) |
|
494 @type QSize |
|
495 """ |
|
496 fragment = self.url().fragment() |
|
497 self.runJavaScript(Scripts.scrollToAnchor(fragment)) |
|
498 |
|
499 ############################################## |
|
500 ## Methods below deal with JavaScript messages |
|
501 ############################################## |
|
502 |
|
503 def javaScriptConsoleMessage(self, level, message, lineNumber, sourceId): |
|
504 """ |
|
505 Public method to show a console message. |
|
506 |
|
507 @param level severity |
|
508 @type QWebEnginePage.JavaScriptConsoleMessageLevel |
|
509 @param message message to be shown |
|
510 @type str |
|
511 @param lineNumber line number of an error |
|
512 @type int |
|
513 @param sourceId source URL causing the error |
|
514 @type str |
|
515 """ |
|
516 self.view().mainWindow().javascriptConsole().javaScriptConsoleMessage( |
|
517 level, message, lineNumber, sourceId) |
|
518 |
|
519 ########################################################################### |
|
520 ## Methods below implement safe browsing related functions |
|
521 ########################################################################### |
|
522 |
|
523 def getSafeBrowsingStatus(self): |
|
524 """ |
|
525 Public method to get the safe browsing status of the current page. |
|
526 |
|
527 @return flag indicating a safe site |
|
528 @rtype bool |
|
529 """ |
|
530 return not self.__badSite |
|
531 |
|
532 ################################################## |
|
533 ## Methods below implement compatibility functions |
|
534 ################################################## |
|
535 |
|
536 if not hasattr(QWebEnginePage, "icon"): |
|
537 def icon(self): |
|
538 """ |
|
539 Public method to get the web site icon. |
|
540 |
|
541 @return web site icon |
|
542 @rtype QIcon |
|
543 """ |
|
544 return self.view().icon() |
|
545 |
|
546 if not hasattr(QWebEnginePage, "scrollPosition"): |
|
547 def scrollPosition(self): |
|
548 """ |
|
549 Public method to get the scroll position of the web page. |
|
550 |
|
551 @return scroll position |
|
552 @rtype QPointF |
|
553 """ |
|
554 pos = self.execJavaScript( |
|
555 "(function() {" |
|
556 "var res = {" |
|
557 " x: 0," |
|
558 " y: 0," |
|
559 "};" |
|
560 "res.x = window.scrollX;" |
|
561 "res.y = window.scrollY;" |
|
562 "return res;" |
|
563 "})()", |
|
564 WebBrowserPage.SafeJsWorld |
|
565 ) |
|
566 pos = ( |
|
567 QPointF(0.0, 0.0) if pos is None |
|
568 else QPointF(pos["x"], pos["y"]) |
|
569 ) |
|
570 |
|
571 return pos |
|
572 |
|
573 ############################################################# |
|
574 ## Methods below implement protocol handler related functions |
|
575 ############################################################# |
|
576 |
|
577 @pyqtSlot("QWebEngineRegisterProtocolHandlerRequest") |
|
578 def __registerProtocolHandlerRequested(self, request): |
|
579 """ |
|
580 Private slot to handle the registration of a custom protocol |
|
581 handler. |
|
582 |
|
583 @param request reference to the registration request |
|
584 @type QWebEngineRegisterProtocolHandlerRequest |
|
585 """ |
|
586 from PyQt5.QtWebEngineCore import ( |
|
587 QWebEngineRegisterProtocolHandlerRequest |
|
588 ) |
|
589 |
|
590 if self.__registerProtocolHandlerRequest: |
|
591 del self.__registerProtocolHandlerRequest |
|
592 self.__registerProtocolHandlerRequest = None |
|
593 self.__registerProtocolHandlerRequest = ( |
|
594 QWebEngineRegisterProtocolHandlerRequest(request) |
|
595 ) |
|
596 |
|
597 def registerProtocolHandlerRequestUrl(self): |
|
598 """ |
|
599 Public method to get the registered protocol handler request URL. |
|
600 |
|
601 @return registered protocol handler request URL |
|
602 @rtype QUrl |
|
603 """ |
|
604 if ( |
|
605 self.__registerProtocolHandlerRequest and |
|
606 (self.url().host() == |
|
607 self.__registerProtocolHandlerRequest.origin().host()) |
|
608 ): |
|
609 return self.__registerProtocolHandlerRequest.origin() |
|
610 else: |
|
611 return QUrl() |
|
612 |
|
613 def registerProtocolHandlerRequestScheme(self): |
|
614 """ |
|
615 Public method to get the registered protocol handler request scheme. |
|
616 |
|
617 @return registered protocol handler request scheme |
|
618 @rtype str |
|
619 """ |
|
620 if ( |
|
621 self.__registerProtocolHandlerRequest and |
|
622 (self.url().host() == |
|
623 self.__registerProtocolHandlerRequest.origin().host()) |
|
624 ): |
|
625 return self.__registerProtocolHandlerRequest.scheme() |
|
626 else: |
|
627 return "" |
|
628 |
|
629 ############################################################# |
|
630 ## SSL configuration handling below |
|
631 ############################################################# |
|
632 |
|
633 def setSslConfiguration(self, sslConfiguration): |
|
634 """ |
|
635 Public slot to set the SSL configuration data of the page. |
|
636 |
|
637 @param sslConfiguration SSL configuration to be set |
|
638 @type QSslConfiguration |
|
639 """ |
|
640 self.__sslConfiguration = QSslConfiguration(sslConfiguration) |
|
641 self.__sslConfiguration.url = self.url() |
|
642 self.sslConfigurationChanged.emit() |
|
643 |
|
644 def getSslConfiguration(self): |
|
645 """ |
|
646 Public method to return a reference to the current SSL configuration. |
|
647 |
|
648 @return reference to the SSL configuration in use |
|
649 @rtype QSslConfiguration |
|
650 """ |
|
651 return self.__sslConfiguration |
|
652 |
|
653 def clearSslConfiguration(self): |
|
654 """ |
|
655 Public slot to clear the stored SSL configuration data. |
|
656 """ |
|
657 self.__sslConfiguration = None |
|
658 self.sslConfigurationChanged.emit() |
|
659 |
|
660 def getSslCertificate(self): |
|
661 """ |
|
662 Public method to get a reference to the SSL certificate. |
|
663 |
|
664 @return amended SSL certificate |
|
665 @rtype QSslCertificate |
|
666 """ |
|
667 if self.__sslConfiguration is None: |
|
668 return None |
|
669 |
|
670 sslCertificate = self.__sslConfiguration.peerCertificate() |
|
671 sslCertificate.url = QUrl(self.__sslConfiguration.url) |
|
672 return sslCertificate |
|
673 |
|
674 def getSslCertificateChain(self): |
|
675 """ |
|
676 Public method to get a reference to the SSL certificate chain. |
|
677 |
|
678 @return SSL certificate chain |
|
679 @rtype list of QSslCertificate |
|
680 """ |
|
681 if self.__sslConfiguration is None: |
|
682 return [] |
|
683 |
|
684 chain = self.__sslConfiguration.peerCertificateChain() |
|
685 return chain |
|
686 |
|
687 def showSslInfo(self, pos): |
|
688 """ |
|
689 Public slot to show some SSL information for the loaded page. |
|
690 |
|
691 @param pos position to show the info at |
|
692 @type QPoint |
|
693 """ |
|
694 if SSL_AVAILABLE and self.__sslConfiguration is not None: |
|
695 from E5Network.E5SslInfoWidget import E5SslInfoWidget |
|
696 widget = E5SslInfoWidget(self.url(), self.__sslConfiguration, |
|
697 self.view()) |
|
698 widget.showAt(pos) |
|
699 else: |
|
700 E5MessageBox.warning( |
|
701 self.view(), |
|
702 self.tr("SSL Info"), |
|
703 self.tr("""This site does not contain SSL information.""")) |
|
704 |
|
705 def hasValidSslInfo(self): |
|
706 """ |
|
707 Public method to check, if the page has a valid SSL certificate. |
|
708 |
|
709 @return flag indicating a valid SSL certificate |
|
710 @rtype bool |
|
711 """ |
|
712 if self.__sslConfiguration is None: |
|
713 return False |
|
714 |
|
715 certList = self.__sslConfiguration.peerCertificateChain() |
|
716 if not certList: |
|
717 return False |
|
718 |
|
719 certificateDict = Globals.toDict( |
|
720 Preferences.Prefs.settings.value("Ssl/CaCertificatesDict")) |
|
721 for server in certificateDict: |
|
722 localCAList = QSslCertificate.fromData(certificateDict[server]) |
|
723 if any(cert in localCAList for cert in certList): |
|
724 return True |
|
725 |
|
726 return all(not cert.isBlacklisted() for cert in certList) |