Sun, 12 Dec 2010 19:44:20 +0100
Started implementing the certificate manager.
--- a/Helpviewer/HelpWindow.py Sun Dec 12 17:22:24 2010 +0100 +++ b/Helpviewer/HelpWindow.py Sun Dec 12 19:44:20 2010 +0100 @@ -36,7 +36,7 @@ from .History.HistoryManager import HistoryManager from .History.HistoryMenu import HistoryMenu from .Passwords.PasswordManager import PasswordManager -from .Network.NetworkAccessManager import NetworkAccessManager +from .Network.NetworkAccessManager import NetworkAccessManager, SSL_AVAILABLE from .AdBlock.AdBlockManager import AdBlockManager from .OfflineStorage.OfflineStorageConfigDialog import OfflineStorageConfigDialog from .UserAgent.UserAgentMenu import UserAgentMenu @@ -1064,6 +1064,20 @@ self.adblockAct.triggered[()].connect(self.__showAdBlockDialog) self.__actions.append(self.adblockAct) + self.certificatesAct = E5Action(self.trUtf8('Manage Certificates'), + self.trUtf8('Manage Certificates...'), + 0, 0, + self, 'help_manage_certificates') + self.certificatesAct.setStatusTip(self.trUtf8( + 'Manage the saved certificates')) + self.certificatesAct.setWhatsThis(self.trUtf8( + """<b>Manage Saved Certificates...</b>""" + """<p>Opens a dialog to manage the saved certificates.</p>""" + )) + if not self.initShortcutsOnly: + self.certificatesAct.triggered[()].connect(self.__showCertificatesDialog) + self.__actions.append(self.certificatesAct) + self.toolsMonitorAct = E5Action(self.trUtf8('Show Network Monitor'), self.trUtf8('Show &Network Monitor'), 0, 0, @@ -1199,6 +1213,8 @@ menu.addAction(self.searchEnginesAct) menu.addSeparator() menu.addAction(self.passwordsAct) + if SSL_AVAILABLE: + menu.addAction(self.certificatesAct) menu.addSeparator() menu.addAction(self.adblockAct) menu.addSeparator() @@ -2268,6 +2284,15 @@ dlg = PasswordsDialog(self) dlg.exec_() + def __showCertificatesDialog(self): + """ + Private slot to show the certificates management dialog. + """ + from .SslCertificatesDialog import SslCertificatesDialog + + dlg = SslCertificatesDialog(self) + dlg.exec_() + def __showAdBlockDialog(self): """ Private slot to show the AdBlock configuration dialog.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Helpviewer/SslCertificatesDialog.py Sun Dec 12 19:44:20 2010 +0100 @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2010 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show and edit all certificates. +""" + +from PyQt4.QtCore import pyqtSlot, Qt +from PyQt4.QtGui import QDialog, QTreeWidgetItem +try: + from PyQt4.QtNetwork import QSslCertificate +except ImportError: + pass + +from .Ui_SslCertificatesDialog import Ui_SslCertificatesDialog + +from .SslInfoDialog import SslInfoDialog + +import Preferences + +class SslCertificatesDialog(QDialog, Ui_SslCertificatesDialog): + """ + Class implementing a dialog to show and edit all certificates. + """ + CertRole = Qt.UserRole + 1 + + def __init__(self, parent = None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + QDialog.__init__(self, parent) + self.setupUi(self) + + self.__populateServerCertificatesTree() + + def __populateServerCertificatesTree(self): + """ + Private slot to populate the server certificates tree. + """ + certificateDict = Preferences.toDict( + Preferences.Prefs.settings.value("Help/CaCertificatesDict")) + for server in certificateDict: + for cert in QSslCertificate.fromData(certificateDict[server]): + self.__createCertificateEntry(self.serversCertificatesTree, server, cert) + + self.serversCertificatesTree.expandAll() + for i in range(self.serversCertificatesTree.columnCount()): + self.serversCertificatesTree.resizeColumnToContents(i) + + def __createCertificateEntry(self, tree, server, cert): + """ + Private method to create a certificate entry. + + @param tree reference to the tree to insert the certificate (QTreeWidget) + @param server server name of the certificate (string) + @param cert certificate to insert (QSslCertificate) + """ + # step 1: extract the info to be shown + organisation = cert.subjectInfo(QSslCertificate.Organization) + if organisation is None or organisation == "": + organisation = self.trUtf8("(Unknown)") + commonName = cert.subjectInfo(QSslCertificate.CommonName) + if commonName is None or commonName == "": + commonName = self.trUtf8("(Unknown common name)") + expiryDate = cert.expiryDate().toString("yyyy-MM-dd") + + # step 2: create the entry + items = tree.findItems(organisation, Qt.MatchFixedString | Qt.MatchCaseSensitive) + if len(items) == 0: + parent = QTreeWidgetItem(tree, [organisation]) + else: + parent = items[0] + + itm = QTreeWidgetItem(parent, [commonName, server, expiryDate]) + itm.setData(0, self.CertRole, cert) + + @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) + def on_serversCertificatesTree_currentItemChanged(self, current, previous): + """ + Private slot handling a change of the current item. + + @param current new current item (QTreeWidgetItem) + @param previous previous current item (QTreeWidgetItem) + """ + enable = current is not None and current.parent() is not None + self.serversViewButton.setEnabled(enable) + self.serversDeleteButton.setEnabled(enable) + + @pyqtSlot() + def on_serversViewButton_clicked(self): + """ + Private slot to show data of the selected certificate + """ + cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole) + dlg = SslInfoDialog(cert, self) + dlg.exec_() + + @pyqtSlot() + def on_serversDeleteButton_clicked(self): + """ + Slot documentation goes here. + """ + # TODO: not implemented yet + raise NotImplementedError
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Helpviewer/SslCertificatesDialog.ui Sun Dec 12 19:44:20 2010 +0100 @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SslCertificatesDialog</class> + <widget class="QDialog" name="SslCertificatesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>760</width> + <height>440</height> + </rect> + </property> + <property name="windowTitle"> + <string>SSL Certificate Manager</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="serversTab"> + <attribute name="title"> + <string>&Servers</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>You have saved certificates identifying these servers:</string> + </property> + </widget> + </item> + <item> + <widget class="QTreeWidget" name="serversCertificatesTree"> + <column> + <property name="text"> + <string>Certificate name</string> + </property> + </column> + <column> + <property name="text"> + <string>Server</string> + </property> + </column> + <column> + <property name="text"> + <string>Expiry Date</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="serversViewButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to view the selected certificate</string> + </property> + <property name="text"> + <string>&View...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="serversDeleteButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to delete the selected certificate</string> + </property> + <property name="text"> + <string>&Delete...</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="caTab"> + <attribute name="title"> + <string>Certificate &Authorities</string> + </attribute> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>serversCertificatesTree</tabstop> + <tabstop>serversViewButton</tabstop> + <tabstop>serversDeleteButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>SslCertificatesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>SslCertificatesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- a/eric5.e4p Sun Dec 12 17:22:24 2010 +0100 +++ b/eric5.e4p Sun Dec 12 19:44:20 2010 +0100 @@ -833,6 +833,7 @@ <Source>ThirdParty/Pygments/pygments/lexers/_asybuiltins.py</Source> <Source>ThirdParty/Pygments/pygments/styles/monokai.py</Source> <Source>Preferences/ConfigurationPages/TrayStarterPage.py</Source> + <Source>Helpviewer/SslCertificatesDialog.py</Source> </Sources> <Forms> <Form>PyUnit/UnittestDialog.ui</Form> @@ -1066,6 +1067,7 @@ <Form>Helpviewer/Download/DownloadItem.ui</Form> <Form>Helpviewer/Download/DownloadManager.ui</Form> <Form>Preferences/ConfigurationPages/TrayStarterPage.ui</Form> + <Form>Helpviewer/SslCertificatesDialog.ui</Form> </Forms> <Translations> <Translation>i18n/eric5_cs.qm</Translation>