|
|
@@ -0,0 +1,221 @@
|
|
|
+/*
|
|
|
+ * Copyright (C) by Klaas Freitag <freitag@kde.org>
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
+ * (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
+ * for more details.
|
|
|
+ */
|
|
|
+#include "sslerrordialog.h"
|
|
|
+#include "mirall/mirallconfigfile.h"
|
|
|
+
|
|
|
+#include <QtGui>
|
|
|
+#include <QtNetwork>
|
|
|
+
|
|
|
+namespace Mirall
|
|
|
+{
|
|
|
+#define CA_CERTS_KEY QLatin1String("CaCertificates")
|
|
|
+
|
|
|
+SslErrorDialog::SslErrorDialog(QWidget *parent) :
|
|
|
+ QDialog(parent), _allTrusted(false)
|
|
|
+{
|
|
|
+ setupUi( this );
|
|
|
+ setWindowTitle( tr("SSL Connection") );
|
|
|
+ QPushButton *okBFutton =
|
|
|
+ _dialogButtonBox->button( QDialogButtonBox::Ok );
|
|
|
+ QPushButton *cancelButton =
|
|
|
+ _dialogButtonBox->button( QDialogButtonBox::Cancel );
|
|
|
+ okBFutton->setEnabled(false);
|
|
|
+ connect(_cbTrustConnect, SIGNAL(clicked(bool)),
|
|
|
+ okBFutton, SLOT(setEnabled(bool)));
|
|
|
+
|
|
|
+ if( okBFutton ) {
|
|
|
+ okBFutton->setDefault(true);
|
|
|
+ connect( okBFutton, SIGNAL(clicked()),SLOT(accept()));
|
|
|
+ connect( cancelButton, SIGNAL(clicked()),SLOT(reject()));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+QList<QSslCertificate> SslErrorDialog::storedCACerts()
|
|
|
+{
|
|
|
+ MirallConfigFile cfg( _customConfigHandle );
|
|
|
+
|
|
|
+ QList<QSslCertificate> cacerts = QSslCertificate::fromData(cfg.caCerts());
|
|
|
+
|
|
|
+ return cacerts;
|
|
|
+}
|
|
|
+
|
|
|
+QString SslErrorDialog::styleSheet() const
|
|
|
+{
|
|
|
+ const QString style = QLatin1String(
|
|
|
+ "#cert {margin-left: 5px;} "
|
|
|
+ "#ca_error { color:#a00011; margin-left:5px; margin-right:5px; }"
|
|
|
+ "#ca_error p { margin-top: 2px; margin-bottom:2px; }"
|
|
|
+ "#ccert { margin-left: 5px; }"
|
|
|
+ "#issuer { margin-left: 5px; }"
|
|
|
+ "tt { font-size: small; }"
|
|
|
+ );
|
|
|
+
|
|
|
+ return style;
|
|
|
+}
|
|
|
+#define QL(x) QLatin1String(x)
|
|
|
+
|
|
|
+bool SslErrorDialog::setErrorList( QList<QSslError> errors )
|
|
|
+{
|
|
|
+ QList<QSslCertificate> ourCerts = storedCACerts();
|
|
|
+
|
|
|
+ // check if unknown certs caused errors.
|
|
|
+ _unknownCerts.clear();
|
|
|
+
|
|
|
+ QStringList errorStrings;
|
|
|
+ for (int i = 0; i < errors.count(); ++i) {
|
|
|
+ if (ourCerts.contains(errors.at(i).certificate()) ||
|
|
|
+ _unknownCerts.contains(errors.at(i).certificate() ))
|
|
|
+ continue;
|
|
|
+ errorStrings += errors.at(i).errorString();
|
|
|
+ if (!errors.at(i).certificate().isNull()) {
|
|
|
+ _unknownCerts.append(errors.at(i).certificate());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // if there are no errors left, all Certs were known.
|
|
|
+ if (errorStrings.isEmpty()) {
|
|
|
+ _allTrusted = true;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ QString msg = QL("<html><head>");
|
|
|
+ msg += QL("<link rel='stylesheet' type='text/css' href='format.css'>");
|
|
|
+ msg += QL("</head><body>");
|
|
|
+
|
|
|
+ // loop over the unknown certs and line up their errors.
|
|
|
+ msg += QL("<h3>") + tr("Warnings about current SSL Connection:") + QL("</h3>");
|
|
|
+ msg += QL("<div id=\"ca_errors\">");
|
|
|
+ foreach( const QSslCertificate& cert, _unknownCerts ) {
|
|
|
+ msg += QL("<div id=\"ca_error\">");
|
|
|
+ // add the errors for this cert
|
|
|
+ foreach( QSslError err, errors ) {
|
|
|
+ if( err.certificate() == cert ) {
|
|
|
+ msg += QL("<p>") + err.errorString() + QL("</p>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ msg += QL("</div>");
|
|
|
+ msg += certDiv( cert );
|
|
|
+ if( _unknownCerts.count() > 1 ) {
|
|
|
+ msg += QL("<hr/>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ msg += QL("</div></body></html>");
|
|
|
+
|
|
|
+ qDebug() << "# # # # # # ";
|
|
|
+ qDebug() << msg;
|
|
|
+ QTextDocument *doc = new QTextDocument(0);
|
|
|
+ QString style = styleSheet();
|
|
|
+ qDebug() << "Style: " << style;
|
|
|
+ doc->addResource( QTextDocument::StyleSheetResource, QUrl( QL("format.css") ), style);
|
|
|
+ doc->setHtml( msg );
|
|
|
+
|
|
|
+ _tbErrors->setDocument( doc );
|
|
|
+ _tbErrors->show();
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static QByteArray formatHash(const QByteArray &fmhash)
|
|
|
+{
|
|
|
+ QByteArray hash;
|
|
|
+ int steps = fmhash.length()/2;
|
|
|
+ for (int i = 0; i < steps; i++) {
|
|
|
+ hash.append(fmhash[i]);
|
|
|
+ hash.append(fmhash[i+1]);
|
|
|
+ hash.append(' ');
|
|
|
+ }
|
|
|
+ return hash;
|
|
|
+}
|
|
|
+
|
|
|
+QString SslErrorDialog::certDiv( QSslCertificate cert ) const
|
|
|
+{
|
|
|
+ QString msg;
|
|
|
+ msg += QL("<div id=\"cert\">");
|
|
|
+ msg += QL("<h3>") + tr("with Certificate %1").arg( cert.subjectInfo( QSslCertificate::CommonName )) + QL("</h3>");
|
|
|
+
|
|
|
+ msg += QL("<div id=\"ccert\">");
|
|
|
+ QStringList li;
|
|
|
+
|
|
|
+ QString org = Qt::escape(cert.subjectInfo( QSslCertificate::Organization));
|
|
|
+ QString unit = Qt::escape(cert.subjectInfo( QSslCertificate::OrganizationalUnitName));
|
|
|
+ QString country = Qt::escape(cert.subjectInfo( QSslCertificate::CountryName));
|
|
|
+ if (unit.isEmpty()) unit = tr("<not specified>");
|
|
|
+ if (org.isEmpty()) org = tr("<not specified>");
|
|
|
+ if (country.isEmpty()) country = tr("<not specified>");
|
|
|
+ li << tr("Organization: %1").arg(org);
|
|
|
+ li << tr("Unit: %1").arg(unit);
|
|
|
+ li << tr("Country: %1").arg(country);
|
|
|
+ msg += QL("<p>") + li.join(QL("<br/>")) + QL("</p>");
|
|
|
+
|
|
|
+ msg += QL("<p>");
|
|
|
+
|
|
|
+ QString md5sum = QString::fromAscii(formatHash(cert.digest(QCryptographicHash::Md5).toHex()));
|
|
|
+ QString sha1sum = QString::fromAscii(formatHash(cert.digest(QCryptographicHash::Sha1).toHex()));
|
|
|
+ msg += tr("Fingerprint (MD5): <tt>%1</tt>").arg(md5sum) + QL("<br/>");
|
|
|
+ msg += tr("Fingerprint (SHA1): <tt>%1</tt>").arg(sha1sum) + QL("<br/>");
|
|
|
+ msg += QL("<br/>");
|
|
|
+ msg += tr("Effective Date: %1").arg( cert.effectiveDate().toString()) + QL("<br/>");
|
|
|
+ msg += tr("Expiry Date: %1").arg( cert.expiryDate().toString()) + QL("</p>");
|
|
|
+
|
|
|
+ msg += QL("</div>" );
|
|
|
+
|
|
|
+ msg += QL("<h3>") + tr("Issuer: %1").arg(Qt::escape(cert.issuerInfo( QSslCertificate::CommonName))) + QL("</h3>");
|
|
|
+ msg += QL("<div id=\"issuer\">");
|
|
|
+ li.clear();
|
|
|
+ li << tr("Organization: %1").arg(Qt::escape(cert.issuerInfo( QSslCertificate::Organization)));
|
|
|
+ li << tr("Unit: %1").arg(Qt::escape(cert.issuerInfo( QSslCertificate::OrganizationalUnitName)));
|
|
|
+ li << tr("Country: %1").arg(Qt::escape(cert.issuerInfo( QSslCertificate::CountryName)));
|
|
|
+ msg += QL("<p>") + li.join(QL("<br/>")) + QL("</p>");
|
|
|
+ msg += QL("</div>" );
|
|
|
+ msg += QL("</div>" );
|
|
|
+
|
|
|
+ return msg;
|
|
|
+}
|
|
|
+
|
|
|
+bool SslErrorDialog::trustConnection()
|
|
|
+{
|
|
|
+ if( _allTrusted ) return true;
|
|
|
+
|
|
|
+ bool stat = ( _cbTrustConnect->checkState() == Qt::Checked );
|
|
|
+ qDebug() << "SSL-Connection is trusted: " << stat;
|
|
|
+
|
|
|
+ return stat;
|
|
|
+}
|
|
|
+
|
|
|
+void SslErrorDialog::accept()
|
|
|
+{
|
|
|
+ // Save the contents of _unknownCerts to the settings file.
|
|
|
+ if( trustConnection() && _unknownCerts.count() > 0 ) {
|
|
|
+ QSslSocket::addDefaultCaCertificates(_unknownCerts);
|
|
|
+
|
|
|
+ MirallConfigFile cfg( _customConfigHandle );
|
|
|
+
|
|
|
+ QByteArray certs = cfg.caCerts();
|
|
|
+
|
|
|
+ qDebug() << "Saving " << _unknownCerts.count() << " unknown certs.";
|
|
|
+ foreach( const QSslCertificate& cert, _unknownCerts ) {
|
|
|
+ certs += cert.toPem() + '\n';
|
|
|
+ }
|
|
|
+ cfg.setCaCerts( certs );
|
|
|
+ }
|
|
|
+
|
|
|
+ QDialog::accept();
|
|
|
+}
|
|
|
+
|
|
|
+void SslErrorDialog::setCustomConfigHandle( const QString& handle )
|
|
|
+{
|
|
|
+ _customConfigHandle = handle;
|
|
|
+}
|
|
|
+
|
|
|
+} // end namespace
|