1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing a widget to show SSL information. 8""" 9 10from PyQt5.QtCore import Qt, QUrl, QPoint 11from PyQt5.QtWidgets import QMenu, QGridLayout, QLabel, QSizePolicy 12from PyQt5.QtNetwork import QSsl, QSslConfiguration, QSslCertificate 13 14import UI.PixmapCache 15import Utilities 16 17 18class E5SslInfoWidget(QMenu): 19 """ 20 Class implementing a widget to show SSL certificate infos. 21 """ 22 def __init__(self, url, configuration, parent=None): 23 """ 24 Constructor 25 26 @param url URL to show SSL info for (QUrl) 27 @param configuration SSL configuration (QSslConfiguration) 28 @param parent reference to the parent widget (QWidget) 29 """ 30 super().__init__(parent) 31 32 self.__url = QUrl(url) 33 self.__configuration = QSslConfiguration(configuration) 34 35 self.setMinimumWidth(400) 36 37 certList = self.__configuration.peerCertificateChain() 38 cert = certList[0] if certList else QSslCertificate() 39 40 layout = QGridLayout(self) 41 rows = 0 42 43 ########################################## 44 ## Identity Information 45 ########################################## 46 imageLabel = QLabel(self) 47 layout.addWidget(imageLabel, rows, 0, Qt.AlignmentFlag.AlignCenter) 48 49 label = QLabel(self) 50 label.setWordWrap(True) 51 label.setSizePolicy(QSizePolicy.Policy.Expanding, 52 QSizePolicy.Policy.Preferred) 53 label.setText(self.tr("Identity")) 54 font = label.font() 55 font.setBold(True) 56 label.setFont(font) 57 layout.addWidget(label, rows, 1) 58 rows += 1 59 60 label = QLabel(self) 61 label.setWordWrap(True) 62 if cert.isNull(): 63 label.setText(self.tr( 64 "Warning: this site is NOT carrying a certificate.")) 65 imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32")) 66 else: 67 valid = not cert.isBlacklisted() 68 if valid: 69 txt = ", ".join( 70 cert.issuerInfo(QSslCertificate.SubjectInfo.CommonName)) 71 label.setText(self.tr( 72 "The certificate for this site is valid" 73 " and has been verified by:\n{0}").format( 74 Utilities.decodeString(txt))) 75 imageLabel.setPixmap( 76 UI.PixmapCache.getPixmap("securityHigh32")) 77 else: 78 label.setText(self.tr( 79 "The certificate for this site is NOT valid.")) 80 imageLabel.setPixmap( 81 UI.PixmapCache.getPixmap("securityLow32")) 82 layout.addWidget(label, rows, 1) 83 rows += 1 84 85 label = QLabel(self) 86 label.setWordWrap(True) 87 label.setText( 88 '<a href="moresslinfos">' + 89 self.tr("Certificate Information") + "</a>") 90 label.linkActivated.connect(self.__showCertificateInfos) 91 layout.addWidget(label, rows, 1) 92 rows += 1 93 94 ########################################## 95 ## Identity Information 96 ########################################## 97 imageLabel = QLabel(self) 98 layout.addWidget(imageLabel, rows, 0, Qt.AlignmentFlag.AlignCenter) 99 100 label = QLabel(self) 101 label.setWordWrap(True) 102 label.setText(self.tr("Encryption")) 103 font = label.font() 104 font.setBold(True) 105 label.setFont(font) 106 layout.addWidget(label, rows, 1) 107 rows += 1 108 109 cipher = self.__configuration.sessionCipher() 110 if cipher.isNull(): 111 label = QLabel(self) 112 label.setWordWrap(True) 113 label.setText(self.tr( 114 'Your connection to "{0}" is NOT encrypted.\n').format( 115 self.__url.host())) 116 layout.addWidget(label, rows, 1) 117 imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32")) 118 rows += 1 119 else: 120 label = QLabel(self) 121 label.setWordWrap(True) 122 label.setText(self.tr( 123 'Your connection to "{0}" is encrypted.').format( 124 self.__url.host())) 125 layout.addWidget(label, rows, 1) 126 127 proto = cipher.protocol() 128 if proto == QSsl.SslProtocol.SslV3: 129 sslVersion = "SSL 3.0" 130 imageLabel.setPixmap( 131 UI.PixmapCache.getPixmap("securityLow32")) 132 elif proto == QSsl.SslProtocol.TlsV1SslV3: 133 sslVersion = "TLS 1.0/SSL 3.0" 134 imageLabel.setPixmap( 135 UI.PixmapCache.getPixmap("securityLow32")) 136 elif proto == QSsl.SslProtocol.SslV2: 137 sslVersion = "SSL 2.0" 138 imageLabel.setPixmap( 139 UI.PixmapCache.getPixmap("securityLow32")) 140 else: 141 sslVersion = self.tr("unknown") 142 imageLabel.setPixmap( 143 UI.PixmapCache.getPixmap("securityLow32")) 144 if proto == QSsl.SslProtocol.TlsV1_0: 145 sslVersion = "TLS 1.0" 146 imageLabel.setPixmap( 147 UI.PixmapCache.getPixmap("securityHigh32")) 148 elif proto == QSsl.SslProtocol.TlsV1_1: 149 sslVersion = "TLS 1.1" 150 imageLabel.setPixmap( 151 UI.PixmapCache.getPixmap("securityHigh32")) 152 elif proto == QSsl.SslProtocol.TlsV1_2: 153 sslVersion = "TLS 1.2" 154 imageLabel.setPixmap( 155 UI.PixmapCache.getPixmap("securityHigh32")) 156 elif proto == QSsl.SslProtocol.TlsV1_3: 157 sslVersion = "TLS 1.3" 158 imageLabel.setPixmap( 159 UI.PixmapCache.getPixmap("securityHigh32")) 160 rows += 1 161 162 label = QLabel(self) 163 label.setWordWrap(True) 164 label.setText(self.tr( 165 "It uses protocol: {0}").format(sslVersion)) 166 layout.addWidget(label, rows, 1) 167 rows += 1 168 169 label = QLabel(self) 170 label.setWordWrap(True) 171 label.setText(self.tr( 172 "It is encrypted using {0} at {1} bits, " 173 "with {2} for message authentication and " 174 "{3} as key exchange mechanism.\n\n").format( 175 cipher.encryptionMethod(), 176 cipher.usedBits(), 177 cipher.authenticationMethod(), 178 cipher.keyExchangeMethod())) 179 layout.addWidget(label, rows, 1) 180 rows += 1 181 182 def showAt(self, pos): 183 """ 184 Public method to show the widget. 185 186 @param pos position to show at (QPoint) 187 """ 188 self.adjustSize() 189 xpos = pos.x() - self.width() 190 if xpos < 0: 191 xpos = 10 192 p = QPoint(xpos, pos.y() + 10) 193 self.move(p) 194 self.show() 195 196 def __showCertificateInfos(self): 197 """ 198 Private slot to show certificate information. 199 """ 200 from .E5SslCertificatesInfoDialog import E5SslCertificatesInfoDialog 201 dlg = E5SslCertificatesInfoDialog( 202 self.__configuration.peerCertificateChain()) 203 dlg.exec() 204 205 def accept(self): 206 """ 207 Public method to accept the widget. 208 """ 209 self.close() 210