From 10e368538ec36b6a5f0c115196fb1177d547a64a Mon Sep 17 00:00:00 2001 From: Tobias Markmann <tm@ayena.de> Date: Sun, 2 Sep 2012 14:30:24 +0200 Subject: Adding Qt based certificate viewer as fallback for Linux. License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php diff --git a/Swift/QtUI/QtCertificateViewerDialog.cpp b/Swift/QtUI/QtCertificateViewerDialog.cpp new file mode 100644 index 0000000..2a1e32a --- /dev/null +++ b/Swift/QtUI/QtCertificateViewerDialog.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtCertificateViewerDialog.h" +#include "ui_QtCertificateViewerDialog.h" + +#include <Swiften/Base/foreach.h> + +#include <QTreeWidgetItem> +#include <QLabel> +#include <QDateTime> + +namespace Swift { + +QtCertificateViewerDialog::QtCertificateViewerDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QtCertificateViewerDialog) { + ui->setupUi(this); + connect(ui->certChainTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); + + setAttribute(Qt::WA_DeleteOnClose); +} + +QtCertificateViewerDialog::~QtCertificateViewerDialog() { + delete ui; +} + +void QtCertificateViewerDialog::setCertificateChain(const std::vector<Certificate::ref> &chain) { + // clean widgets + ui->certChainTreeWidget->clear(); + + if (chain.empty()) return; + + // convert Swift certificate chain to qt certificate chain (root goes first) + currentChain.clear(); + foreach(Certificate::ref cert, chain) { + ByteArray certAsDer = cert->toDER(); + QByteArray dataArray(reinterpret_cast<const char*>(certAsDer.data()), certAsDer.size()); + currentChain.push_front(QSslCertificate(dataArray, QSsl::Der)); + } + + // fill treeWidget + QTreeWidgetItem* root = new QTreeWidgetItem(ui->certChainTreeWidget, QStringList(currentChain.at(0).subjectInfo(QSslCertificate::CommonName))); + root->setData(0, Qt::UserRole, QVariant(0)); + root->setExpanded(true); + ui->certChainTreeWidget->addTopLevelItem(root); + if (currentChain.size() > 1) { + QTreeWidgetItem* parent = root; + for (int n = 1; n < currentChain.size(); n++) { + QTreeWidgetItem* link = new QTreeWidgetItem(parent, QStringList(QString("↳ ") + currentChain.at(n).subjectInfo(QSslCertificate::CommonName))); + link->setExpanded(true); + link->setData(0, Qt::UserRole, QVariant(n)); + parent = link; + } + ui->certChainTreeWidget->setCurrentItem(parent); + } else { + ui->certChainTreeWidget->setCurrentItem(root); + } +} + +void QtCertificateViewerDialog::displayCertificateChainAsSheet(QWidget *parent, const std::vector<Certificate::ref> &chain) { + QtCertificateViewerDialog* dialog = new QtCertificateViewerDialog(parent); + dialog->setCertificateChain(chain); + dialog->show(); +} + +void QtCertificateViewerDialog::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem*) { + setCertificateDetails(currentChain.at(current->data(0, Qt::UserRole).toInt())); +} + +#define ADD_SECTION( TITLE ) \ + ui->certGridLayout->addWidget(new QLabel("<strong>" + TITLE + "</strong>"), rowCount++, 0, 1, 2); + +#define ADD_FIELD( TITLE, VALUE) \ + ui->certGridLayout->addWidget(new QLabel(TITLE), rowCount, 0, 1, 1, Qt::AlignRight); \ + valueLabel = new QLabel(VALUE); \ + valueLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); \ + ui->certGridLayout->addWidget(valueLabel, rowCount++, 1, 1, 1, Qt::AlignLeft); + +void QtCertificateViewerDialog::setCertificateDetails(const QSslCertificate &cert) { + QLayoutItem* item; + while ((item = ui->certGridLayout->takeAt(0)) != NULL ) { + delete item->widget(); + delete item; + } + + int rowCount = 0; + + ui->certGridLayout->setColumnStretch(2, 1); + + QLabel* valueLabel = 0; + + ADD_SECTION(tr("General")); + ADD_FIELD(tr("Valid From"), cert.effectiveDate().toString(Qt::TextDate)); + ADD_FIELD(tr("Valid To"), cert.expiryDate().toString(Qt::TextDate)); + ADD_FIELD(tr("Serial Number"), QString(cert.serialNumber().toHex())); + ADD_FIELD(tr("Version"), QString(cert.version())); + + ADD_SECTION(tr("Subject")); + ADD_FIELD(tr("Organization"), cert.subjectInfo(QSslCertificate::Organization)); + ADD_FIELD(tr("Common Name"), cert.subjectInfo(QSslCertificate::CommonName)); + ADD_FIELD(tr("Locality"), cert.subjectInfo(QSslCertificate::LocalityName)); + ADD_FIELD(tr("Organizational Unit"), cert.subjectInfo(QSslCertificate::OrganizationalUnitName)); + ADD_FIELD(tr("Country"), cert.subjectInfo(QSslCertificate::CountryName)); + ADD_FIELD(tr("State"), cert.subjectInfo(QSslCertificate::StateOrProvinceName)); + + if (!cert.alternateSubjectNames().empty()) { + ADD_SECTION(tr("Alternate Subject Names")); + QMultiMap<QSsl::AlternateNameEntryType, QString> altNames = cert.alternateSubjectNames(); + foreach (const QSsl::AlternateNameEntryType &type, altNames.uniqueKeys()) { + foreach (QString name, altNames.values(type)) { + if (type == QSsl::EmailEntry) { + ADD_FIELD(tr("E-mail Address"), name); + } else { + ADD_FIELD(tr("DNS Name"), name); + } + } + } + } + + ADD_SECTION(tr("Issuer")); + ADD_FIELD(tr("Organization"), cert.issuerInfo(QSslCertificate::Organization)); + ADD_FIELD(tr("Common Name"), cert.issuerInfo(QSslCertificate::CommonName)); + ADD_FIELD(tr("Locality"), cert.issuerInfo(QSslCertificate::LocalityName)); + ADD_FIELD(tr("Organizational Unit"), cert.issuerInfo(QSslCertificate::OrganizationalUnitName)); + ADD_FIELD(tr("Country"), cert.issuerInfo(QSslCertificate::CountryName)); + ADD_FIELD(tr("State"), cert.issuerInfo(QSslCertificate::StateOrProvinceName)); + + ui->certGridLayout->setRowStretch(rowCount + 1, 1); +} + +} diff --git a/Swift/QtUI/QtCertificateViewerDialog.h b/Swift/QtUI/QtCertificateViewerDialog.h new file mode 100644 index 0000000..9475a83 --- /dev/null +++ b/Swift/QtUI/QtCertificateViewerDialog.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <QDialog> +#include <QList> +#include <QSslCertificate> +#include <QTreeWidgetItem> + +#include <Swiften/TLS/Certificate.h> + +namespace Ui { +class QtCertificateViewerDialog; +} + +namespace Swift { + +class QtCertificateViewerDialog : public QDialog { + Q_OBJECT + + public: + explicit QtCertificateViewerDialog(QWidget* parent = 0); + ~QtCertificateViewerDialog(); + + void setCertificateChain(const std::vector<Certificate::ref>& chain); + + static void displayCertificateChainAsSheet(QWidget* parent, const std::vector<Certificate::ref>& chain); + + private slots: + void currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); + + private: + void setCertificateDetails(const QSslCertificate& cert); + + private: + Ui::QtCertificateViewerDialog *ui; + QList<QSslCertificate> currentChain; +}; + +} diff --git a/Swift/QtUI/QtCertificateViewerDialog.ui b/Swift/QtUI/QtCertificateViewerDialog.ui new file mode 100644 index 0000000..63a96bf --- /dev/null +++ b/Swift/QtUI/QtCertificateViewerDialog.ui @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QtCertificateViewerDialog</class> + <widget class="QDialog" name="QtCertificateViewerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>655</width> + <height>514</height> + </rect> + </property> + <property name="windowTitle"> + <string>Certificate Viewer</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0"> + <item row="3" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QScrollArea" name="scrollArea"> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>629</width> + <height>368</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="certGridLayout"/> + </item> + </layout> + </widget> + </widget> + </item> + <item row="0" column="0"> + <widget class="QTreeWidget" name="certChainTreeWidget"> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>70</height> + </size> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="showDropIndicator" stdset="0"> + <bool>false</bool> + </property> + <property name="dragEnabled"> + <bool>false</bool> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <property name="expandsOnDoubleClick"> + <bool>false</bool> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string notr="true">1</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>QtCertificateViewerDialog</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>QtCertificateViewerDialog</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> diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index ced375f..5d50c1e 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -41,6 +41,8 @@ #include <Swift/QtUI/CocoaUIHelpers.h> #elif defined(SWIFTEN_PLATFORM_WINDOWS) #include <Swift/QtUI/WinUIHelpers.h> +#else +#include <Swift/QtUI/QtCertificateViewerDialog.h> #endif namespace Swift { @@ -309,7 +311,7 @@ void QtMainWindow::openCertificateDialog(const std::vector<Certificate::ref>& ch #elif defined(SWIFTEN_PLATFORM_WINDOWS) WinUIHelpers::displayCertificateChainAsSheet(parent, chain); #else -#pragma message ("No certificate dialog available on this platform.") + QtCertificateViewerDialog::displayCertificateChainAsSheet(parent, chain); #endif } diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 27ff237..a8a87de 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -51,6 +51,9 @@ myenv.Tool("textfile", toolpath = ["#/BuildTools/SCons/Tools"]) qt4modules = ['QtCore', 'QtGui', 'QtWebKit'] if env["PLATFORM"] == "posix" : qt4modules += ["QtDBus"] +if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" : + qt4modules += ["QtNetwork"] + myenv.EnableQt4Modules(qt4modules, debug = False) myenv.Append(CPPPATH = ["."]) @@ -185,6 +188,8 @@ if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" : swiftProgram = myenv.Program("Swift", sources) else : swiftProgram = myenv.Program("swift-im", sources) + sources += ["QtCertificateViewerDialog.cpp"]; + myenv.Uic4("QtCertificateViewerDialog.ui"); if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" : openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp") -- cgit v0.10.2-6-g49f6