From a496f3dc5b9efdde195f82c2e9052081eef06aaa Mon Sep 17 00:00:00 2001 From: konrad Date: Thu, 24 Dec 2009 17:36:28 +0000 Subject: [PATCH] SSL handling complete git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@350 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- src/configdialog.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++--- src/configdialog.h | 16 ++++++- src/sslexception.cpp | 75 +++++++++++++++++++++++++--- src/sslexception.h | 27 ++++++++-- 4 files changed, 227 insertions(+), 23 deletions(-) diff --git a/src/configdialog.cpp b/src/configdialog.cpp index 1ee01d3..4dc2116 100644 --- a/src/configdialog.cpp +++ b/src/configdialog.cpp @@ -15,6 +15,7 @@ #include "configdialog.h" #include "office.h" #include "listview.h" +#include "sslexception.h" #include #include @@ -31,16 +32,23 @@ #include #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include MConfigDialog::MConfigDialog() { setWindowTitle(tr("Magic Smoke Configuration")); oldrow=-1; + sslexcept=0; //main layout QHBoxLayout*hl; QVBoxLayout*vl; @@ -66,23 +74,22 @@ MConfigDialog::MConfigDialog() m->addAction(tr("Set &Default Label Font..."),this,SLOT(setDefaultFont())); mb->addMenu(MApplication::helpMenu()); - //create central widget - QGridLayout*gl; + //create list view hl->addWidget(profiles=new MListView); profilemodel=new QStandardItemModel(this); profiles->setModel(profilemodel); profiles->setEditTriggers(QListView::NoEditTriggers); connect(profiles,SIGNAL(clicked(const QModelIndex&)),this,SLOT(loadProfile())); connect(profiles,SIGNAL(activated(const QModelIndex&)),this,SLOT(loadProfile())); - hl->addLayout(gl=new QGridLayout,10); + //create tabs + QTabWidget*tab; + QWidget*w; + hl->addWidget(tab=new QTabWidget,10); + tab->addTab(w=new QWidget,tr("Connection")); + QGridLayout*gl; + w->setLayout(gl=new QGridLayout); QLabel*lab; int lctr=0; - gl->addWidget(lab=new QLabel(tr("Hostname:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(hostname=new QLineEdit,lctr,1); - gl->addWidget(lab=new QLabel(tr("Hostkey:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(hostkey=new QLineEdit,lctr,1); gl->addWidget(lab=new QLabel(tr("Server URL:")),++lctr,0); lab->setAlignment(Qt::AlignRight); gl->addLayout(hl=new QHBoxLayout,lctr,1); @@ -105,12 +112,37 @@ MConfigDialog::MConfigDialog() proxypass->setEchoMode(QLineEdit::Password); connect(useproxy,SIGNAL(toggled(bool)),proxyuser,SLOT(setEnabled(bool))); connect(useproxy,SIGNAL(toggled(bool)),proxypass,SLOT(setEnabled(bool))); + + tab->addTab(w=new QWidget,tr("Authentication")); + w->setLayout(gl=new QGridLayout); + lctr=0; + gl->addWidget(lab=new QLabel(tr("Hostname:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(hostname=new QLineEdit,lctr,1); + gl->addWidget(lab=new QLabel(tr("Hostkey:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(hostkey=new QLineEdit,lctr,1); gl->addWidget(lab=new QLabel(tr("Default Username:")),++lctr,0); lab->setAlignment(Qt::AlignRight); gl->addWidget(username=new QLineEdit,lctr,1); gl->setRowStretch(++lctr,10); gl->addLayout(hl=new QHBoxLayout,++lctr,0,1,2); + tab->addTab(w=new QWidget,tr("SSL Exceptions")); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("List of non-fatal SSL exceptions:")),0); + vl->addWidget(ssltable=new QTableView,10); + ssltable->setModel(sslmodel=new QStandardItemModel(this)); + ssltable->setEditTriggers(QListView::NoEditTriggers); + vl->addSpacing(10); + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*pb; + hl->addWidget(pb=new QPushButton(tr("Clear"))); + connect(pb,SIGNAL(clicked()),this,SLOT(clearSslExceptions())); + hl->addWidget(pb=new QPushButton(tr("Probe Server"))); + connect(pb,SIGNAL(clicked()),this,SLOT(serverProbe())); + initProfiles(); loadProfile(); } @@ -150,6 +182,8 @@ void MConfigDialog::loadProfile() { //save old saveProfile(); + if(sslexcept)delete sslexcept; + sslexcept=0; //get new QModelIndex idx=profiles->currentIndex(); if(!idx.isValid())return; @@ -170,6 +204,8 @@ void MConfigDialog::loadProfile() proxyuser->setEnabled(useproxy->isChecked()); proxypass->setEnabled(useproxy->isChecked()); username->setText(set.value("username").toString()); + sslexcept=new MSslExceptions(::dataDir+"/profile."+key+"/sslexceptions.xml"); + sslFillModel(); } void MConfigDialog::saveProfile() @@ -187,6 +223,7 @@ void MConfigDialog::saveProfile() set.setValue("proxyuser",proxyuser->text()); set.setValue("proxypass",proxypass->text()); set.setValue("username",username->text()); + if(sslexcept)sslexcept->savesslexcept(); } void MConfigDialog::newProfile() @@ -334,6 +371,11 @@ void MConfigDialog::exportKey() void MConfigDialog::generateKey() { + //ask nicely + if(hostkey->text()!="") + if(QMessageBox::question(this,tr("Generate Hostkey"), tr("Do you really want to generate a new host key for this profile? This may disable all accounts from this host."), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + return; + //actually create new key QString name; MKeyGen mkg(this); QString k=mkg.getKey(); @@ -432,3 +474,75 @@ void MConfigDialog::setDefaultFont() if(df.isEmpty())return; QSettings().setValue("defaultfont",df); } + +void MConfigDialog::serverProbe() +{ + //sanity check + if(!sslexcept)return; + sslexcept->clearRecorded(); + //set up mini-environment + QEventLoop loop; + QNetworkAccessManager man; + connect(&man,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit())); + QTimer::singleShot(30000,&loop,SLOT(quit())); + connect(&man,SIGNAL(sslErrors(QNetworkReply*,const QList&)), this,SLOT(sslErrors(QNetworkReply*,const QList&))); + if(useproxy->isChecked()) + man.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,proxyname->text(),proxyport->value(),proxyuser->text(),proxypass->text())); + //query server + QNetworkRequest rq(QUrl("https://"+serverurl->text())); + QNetworkReply *rp=man.get(rq); + //wait for result + setEnabled(false); + loop.exec(); + setEnabled(true); + //probe result + if(rp->error()==QNetworkReply::NoError){ + QMessageBox::information(this,tr("Server Probe"),tr("The request finished without errors.")); + }else{ + QMessageBox::warning(this,tr("Server Probe"),tr("The request finished with an error: %1").arg(rp->errorString())); + } + delete rp; +} + +void MConfigDialog::sslErrors(QNetworkReply*rp,const QList&errs) +{ + if(!sslexcept)return; + //check/record/clear + if(sslexcept->checksslexcept(errs))rp->ignoreSslErrors(); + //convert to string + QString err=tr("SSL Errors encountered:\n"); + for(int i=0;iignoreSslErrors(); + sslexcept->acceptRecorded(); + } + sslFillModel(); +} + +void MConfigDialog::clearSslExceptions() +{ + if(sslexcept)sslexcept->clear(); + sslmodel->clear(); +} + +void MConfigDialog::sslFillModel() +{ + sslmodel->clear(); + if(!sslexcept)return; + sslmodel->insertColumns(0,3); + sslmodel->setHorizontalHeaderLabels(QStringList()< >lst=sslexcept->nonFatalExceptions(); + sslmodel->insertRows(0,lst.size()); + for(int i=0;isetData(sslmodel->index(i,0),lst[i].first.subjectInfo(QSslCertificate::CommonName)); + sslmodel->setData(sslmodel->index(i,1),QString::fromAscii(lst[i].first.digest(QCryptographicHash::Sha1).toHex())); + sslmodel->setData(sslmodel->index(i,2),QSslError((QSslError::SslError)lst[i].second).errorString()); + } +} diff --git a/src/configdialog.h b/src/configdialog.h index 4d78ff5..279653a 100644 --- a/src/configdialog.h +++ b/src/configdialog.h @@ -14,12 +14,18 @@ #define MAGICSMOKE_CONFIGDIALOG_H #include +#include +#include class QCheckBox; class QLineEdit; class QListView; +class QNetworkReply; class QSpinBox; class QStandardItemModel; +class QTableView; + +class MSslExceptions; /**login and profile configuration window*/ class MConfigDialog:public QDialog @@ -34,7 +40,10 @@ class MConfigDialog:public QDialog QLineEdit*hostname,*hostkey,*serverurl,*proxyname,*username,*proxyuser,*proxypass; QSpinBox*proxyport; QListView*profiles; - QStandardItemModel*profilemodel; + QStandardItemModel*profilemodel,*sslmodel; + QTableView*ssltable; + + MSslExceptions*sslexcept; int oldrow; @@ -58,6 +67,11 @@ class MConfigDialog:public QDialog void generateKey(); void openOfficeCfg(); void setDefaultFont(); + //ssl server probe + void serverProbe(); + void sslErrors(QNetworkReply*,const QList&); + void clearSslExceptions(); + void sslFillModel(); }; #endif diff --git a/src/sslexception.cpp b/src/sslexception.cpp index c9decc0..c060d0a 100644 --- a/src/sslexception.cpp +++ b/src/sslexception.cpp @@ -17,7 +17,6 @@ #include #include #include -#include MSslExceptions::MSslExceptions(QString p) { @@ -29,21 +28,81 @@ MSslExceptions::MSslExceptions(QString p) if(!doc.setContent(&fd))return; fd.close(); QDomElement root=doc.documentElement(); + QDomNodeList nl=root.elementsByTagName("SSL-Exception"); + for(int i=0;i(c,e)); + } } } -void MSslExceptions::savesslexcept(){} +void MSslExceptions::savesslexcept() +{ + QDomDocument doc; + QDomElement root=doc.createElement("SSL-Exceptions"); + for(int i=0;i&errs) { - qDebug("!!!!!!!!!!!!!!!!!!! %i SSL Exceptions!",errs.size()); - return true; + //stage 1: record unknown exceptions + for(int i=0;ip(errs[i].certificate(),errs[i].error()); + bool known=false; + for(int j=0;jp(errs[i].certificate(),errs[i].error()); + bool known=false; + for(int j=0;j #include #include +#include +#include #include #include class QWidget; +/**Helper class: stores and compares SSL-Exceptions*/ class MSslExceptions { public: + /**create instance from file in path*/ MSslExceptions(QString path); - //ssl helper: save the exceptions + /**saves the exceptions to config file for next session*/ void savesslexcept(); - //ssl helper: check errors agains the exception list + /**checks errors against the exception list, records all exceptions*/ bool checksslexcept(const QList&); - void showdialog(QWidget*); - + /**returns the current list of acceptable exceptions*/ + QList > nonFatalExceptions()const{return sslexcept;} + + /**returns the list of collected exceptions*/ + QList > collectedExceptions()const{return sslrecord;} + + /**clears the internal lists of exceptions*/ + void clear(); + + /**clears the list of recorded exceptions*/ + void clearRecorded(){sslrecord.clear();} + + /**accepts the recorded exceptions*/ + void acceptRecorded(); + private: - QMap > sslexcept; + QList > sslexcept,sslrecord; QString path; }; -- 1.7.2.5