diff -r fd7fa26076d2 -r b1a2f9054b28 E5Network/E5SslInfoWidget.py --- a/E5Network/E5SslInfoWidget.py Sat Feb 23 14:25:36 2013 +0100 +++ b/E5Network/E5SslInfoWidget.py Sun Feb 24 20:00:51 2013 +0100 @@ -4,145 +4,184 @@ # """ -Module implementing a widget to show SSL certificate infos. +Module implementing a widget to show SSL information. """ -from PyQt4.QtCore import QCryptographicHash, QDateTime, qVersion -from PyQt4.QtGui import QWidget -from PyQt4.QtNetwork import QSslCertificate +from PyQt4.QtCore import qVersion, Qt, QUrl, QPoint +from PyQt4.QtGui import QMenu, QGridLayout, QLabel, QSizePolicy +from PyQt4.QtNetwork import QSsl, QSslConfiguration, QSslCertificate -from .Ui_E5SslInfoWidget import Ui_E5SslInfoWidget - +import UI.PixmapCache import Utilities -class E5SslInfoWidget(QWidget, Ui_E5SslInfoWidget): +class E5SslInfoWidget(QMenu): """ Class implementing a widget to show SSL certificate infos. """ - def __init__(self, parent=None): + def __init__(self, url, configuration, parent=None): """ Constructor + @param url URL to show SSL info for (QUrl) + @param configuration SSL configuration (QSslConfiguration) @param parent reference to the parent widget (QWidget) """ super().__init__(parent) - self.setupUi(self) - def showCertificate(self, certificate): - """ - Public method to show the SSL certificate information. + self.__url = QUrl(url) + self.__configuration = QSslConfiguration(configuration) + + self.setAttribute(Qt.WA_DeleteOnClose) + self.setMinimumWidth(400) - @param certificate reference to the SSL certificate (QSslCertificate) - """ - self.blacklistedLabel.setVisible(False) - self.blacklistedLabel.setStyleSheet( - "QLabel { color : white; background-color : red; }") - self.expiredLabel.setVisible(False) - self.expiredLabel.setStyleSheet( - "QLabel { color : white; background-color : red; }") + certList = self.__configuration.peerCertificateChain() + if certList: + cert = certList[0] + else: + cert = QSslCertificate() + + layout = QGridLayout(self) + rows = 0 - if qVersion() >= "5.0.0": - self.subjectCommonNameLabel.setText(self.__certificateString( - ", ".join(certificate.subjectInfo(QSslCertificate.CommonName)))) - self.subjectOrganizationLabel.setText(self.__certificateString( - ", ".join(certificate.subjectInfo(QSslCertificate.Organization)))) - self.subjectOrganizationalUnitLabel.setText(self.__certificateString( - ", ".join( - certificate.subjectInfo(QSslCertificate.OrganizationalUnitName)))) - self.issuerCommonNameLabel.setText(self.__certificateString( - ", ".join(certificate.issuerInfo(QSslCertificate.CommonName)))) - self.issuerOrganizationLabel.setText(self.__certificateString( - ", ".join(certificate.issuerInfo(QSslCertificate.Organization)))) - self.issuerOrganizationalUnitLabel.setText(self.__certificateString( - ", ".join(certificate.issuerInfo(QSslCertificate.OrganizationalUnitName)))) + ########################################## + ## Identity Information + ########################################## + imageLabel = QLabel(self) + layout.addWidget(imageLabel, rows, 0, Qt.AlignCenter) + + label = QLabel(self) + label.setWordWrap(True) + label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + label.setText(self.trUtf8("Identity")) + font = label.font() + font.setBold(True) + label.setFont(font) + layout.addWidget(label, rows, 1) + rows += 1 + + label = QLabel(self) + label.setWordWrap(True) + if cert.isNull(): + label.setText( + self.trUtf8("Warning: this site is NOT carrying a certificate.")) + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) else: - self.subjectCommonNameLabel.setText(self.__certificateString( - certificate.subjectInfo(QSslCertificate.CommonName))) - self.subjectOrganizationLabel.setText(self.__certificateString( - certificate.subjectInfo(QSslCertificate.Organization))) - self.subjectOrganizationalUnitLabel.setText(self.__certificateString( - certificate.subjectInfo(QSslCertificate.OrganizationalUnitName))) - self.issuerCommonNameLabel.setText(self.__certificateString( - certificate.issuerInfo(QSslCertificate.CommonName))) - self.issuerOrganizationLabel.setText(self.__certificateString( - certificate.issuerInfo(QSslCertificate.Organization))) - self.issuerOrganizationalUnitLabel.setText(self.__certificateString( - certificate.issuerInfo(QSslCertificate.OrganizationalUnitName))) - self.serialNumberLabel.setText(self.__serialNumber(certificate)) - self.effectiveLabel.setText( - certificate.effectiveDate().toString("yyyy-MM-dd")) - self.expiresLabel.setText( - certificate.expiryDate().toString("yyyy-MM-dd")) - self.sha1Label.setText(self.__formatHexString( - str(certificate.digest(QCryptographicHash.Sha1).toHex(), encoding="ascii"))) - self.md5Label.setText(self.__formatHexString( - str(certificate.digest(QCryptographicHash.Md5).toHex(), encoding="ascii"))) + if qVersion() >= "5.0.0": + valid = not cert.isBlacklisted() + else: + valid = cert.isValid() + if valid: + if qVersion() >= "5.0.0": + txt = ", ".join(cert.issuerInfo(QSslCertificate.CommonName)) + else: + txt = cert.issuerInfo(QSslCertificate.CommonName) + label.setText(self.trUtf8("The certificate for this site is valid" + " and has been verified by:\n{0}").format( + Utilities.decodeString(txt))) + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityHigh32.png")) + else: + label.setText(self.trUtf8("The certificate for this site is NOT valid.")) + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) + layout.addWidget(label, rows, 1) + rows += 1 + + label = QLabel(self) + label.setWordWrap(True) + label.setText('<a href="moresslinfos">' + + self.trUtf8("Certificate Information") + "</a>") + label.linkActivated.connect(self.__showCertificateInfos) + layout.addWidget(label, rows, 1) + rows += 1 + + ########################################## + ## Identity Information + ########################################## + imageLabel = QLabel(self) + layout.addWidget(imageLabel, rows, 0, Qt.AlignCenter) + + label = QLabel(self) + label.setWordWrap(True) + label.setText(self.trUtf8("Encryption")) + font = label.font() + font.setBold(True) + label.setFont(font) + layout.addWidget(label, rows, 1) + rows += 1 - if (qVersion() >= "5.0.0" and certificate.isBlacklisted()) or \ - (qVersion() < "5.0.0" and not certificate.isValid()): - # something is wrong; indicate it to the user - if self.__hasExpired(certificate.effectiveDate(), certificate.expiryDate()): - self.expiredLabel.setVisible(True) + cipher = self.__configuration.sessionCipher() + if cipher.isNull(): + label = QLabel(self) + label.setWordWrap(True) + label.setText(self.trUtf8( + 'Your connection to "{0}" is NOT encrypted.\n').format( + self.__url.host())) + layout.addWidget(label, rows, 1) + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) + rows += 1 + else: + label = QLabel(self) + label.setWordWrap(True) + label.setText(self.trUtf8( + 'Your connection to "{0}" is encrypted.').format( + self.__url.host())) + layout.addWidget(label, rows, 1) + + proto = cipher.protocol() + if proto == QSsl.SslV3: + sslVersion = "SSL 3.0" + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityHigh32.png")) + elif proto == QSsl.TlsV1: + sslVersion = "TLS 1.0" + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityHigh32.png")) + elif proto == QSsl.SslV2: + sslVersion = "SSL 2.0" + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) else: - self.blacklistedLabel.setVisible(True) + sslVersion = self.trUtf8("unknown") + imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) + rows += 1 + + label = QLabel(self) + label.setWordWrap(True) + label.setText(self.trUtf8("It uses protocol: {0}").format(sslVersion)) + layout.addWidget(label, rows, 1) + rows += 1 + + label = QLabel(self) + label.setWordWrap(True) + label.setText(self.trUtf8( + "It is encrypted using {0} at {1} bits, " + "with {2} for message authentication and " + "{3} as key exchange mechanism.\n\n").format( + cipher.encryptionMethod(), + cipher.usedBits(), + cipher.authenticationMethod(), + cipher.keyExchangeMethod())) + layout.addWidget(label, rows, 1) + rows += 1 - def __certificateString(self, txt): - """ - Private method to prepare some text for display. - - @param txt text to be displayed (string) - @return prepared text (string) - """ - if txt is None or txt == "": - return self.trUtf8("<not part of the certificate>") - - return Utilities.decodeString(txt) - - def __serialNumber(self, cert): + def showAt(self, pos): """ - Private slot to format the certificate serial number. + Public method to show the widget. - @param cert reference to the SSL certificate (QSslCertificate) - @return formated serial number (string) + @param pos position to show at (QPoint) """ - serial = cert.serialNumber() - if serial == "": - return self.trUtf8("<not part of the certificate>") - - if ':' in serial: - return str(serial, encoding="ascii").upper() - else: - hexString = hex(int(serial))[2:] - return self.__formatHexString(hexString) + self.adjustSize() + p = QPoint(pos.x() - self.width(), pos.y() + 10) + self.move(p) + self.show() - def __formatHexString(self, hexString): + def __showCertificateInfos(self): """ - Private method to format a hex string for display. - - @param hexString hex string to be formatted (string) - @return formatted string (string) + Private slot to show certificate information. """ - hexString = hexString.upper() - - if len(hexString) % 2 == 1: - hexString = '0' + hexString - - hexList = [] - while hexString: - hexList.append(hexString[:2]) - hexString = hexString[2:] - - return ':'.join(hexList) + from .E5SslCertificatesInfoDialog import E5SslCertificatesInfoDialog + dlg = E5SslCertificatesInfoDialog(self.__configuration.peerCertificateChain()) + dlg.exec_() - def __hasExpired(self, effectiveDate, expiryDate): + def accept(self): """ - Private method to check for a certificate expiration. - - @param effectiveDate date the certificate becomes effective (QDateTime) - @param expiryDate date the certificate expires (QDateTime) - @return flag indicating the expiration status (boolean) + Public method to accept the widget. """ - now = QDateTime.currentDateTime() - - return now < effectiveDate or now >= expiryDate + self.close()