Merge pull request #133 from mamarley/clientreconnectfix
authorManuel Nickschas <sputnick@quassel-irc.org>
Thu, 8 Oct 2015 21:33:54 +0000 (23:33 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Thu, 8 Oct 2015 21:33:54 +0000 (23:33 +0200)
Keep _wantReconnect set to true by default instead of false

13 files changed:
.gitignore [new file with mode: 0644]
CMakeLists.txt
scripts/build/macosx_DeployApp.py
scripts/build/macosx_makebundle.py
src/client/clientauthhandler.cpp
src/client/clientauthhandler.h
src/client/treemodel.cpp
src/common/main.cpp
src/common/peer.h
src/core/coreauthhandler.cpp
src/core/sslserver.cpp
src/core/sslserver.h
src/qtui/CMakeLists.txt

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..a15aef7
--- /dev/null
@@ -0,0 +1,3 @@
+build*
+*.pyc
+tags
index d873973..1a22fac 100644 (file)
@@ -240,7 +240,11 @@ if (USE_QT5)
                 )
             endif()
         endif()
-        add_feature_info("WITH_WEBKIT, QtWebKit and QtWebKitWidgets modules" Qt5WebKitWidgets_FOUND "Support showing previews for URLs in chat")
+
+        if (WITH_WEBKIT AND Qt5WebKitWidgets_FOUND)
+            set(HAVE_WEBKIT true)
+        endif()
+        add_feature_info("WITH_WEBKIT, QtWebKit and QtWebKitWidgets modules" HAVE_WEBKIT "Support showing previews for URLs in chat")
 
         # KDE Frameworks
         ################
@@ -570,10 +574,10 @@ git_describe(GIT_DESCRIBE --long)
 # enviroment
 if (NOT GIT_HEAD OR NOT GIT_DESCRIBE)
   if (DEFINED ENV{GIT_HEAD})
-      set(GIT_HEAD ${GIT_HEAD})
+      set(GIT_HEAD $ENV{GIT_HEAD})
   endif ()
   if (DEFINED ENV{GIT_DESCRIBE})
-     set(GIT_DESCRIBE ${GIT_DESCRIBE})
+     set(GIT_DESCRIBE $ENV{GIT_DESCRIBE})
   endif()
 endif()
 
index c1cddf5..e6cfc1d 100755 (executable)
@@ -32,10 +32,8 @@ QT_CONFIG_NOBUNDLE = """[Paths]
 """
 
 
-
-
 class InstallQt(object):
-    def __init__(self, appdir, bundle = True, requestedPlugins=[]):
+    def __init__(self, appdir, bundle=True, requestedPlugins=[]):
         self.appDir = appdir
         self.bundle = bundle
         self.frameworkDir = self.appDir + "/Frameworks"
@@ -52,7 +50,6 @@ class InstallQt(object):
         for executable in executables:
             self.resolveDependancies(executable)
 
-
         self.findPluginsPath()
         self.installPlugins(requestedPlugins)
         self.installQtConf()
@@ -101,7 +98,6 @@ class InstallQt(object):
             raise OSError
         return result
 
-
     def installPlugins(self, requestedPlugins):
         try:
             os.mkdir(self.pluginDir)
@@ -145,7 +141,7 @@ class InstallQt(object):
 
     def resolveDependancies(self, obj):
         # obj must be either an application binary or a framework library
-        #print "resolving deps for:", obj
+        # print "resolving deps for:", obj
         for framework, lib in self.determineDependancies(obj):
             self.installFramework(framework)
             self.changeDylPath(obj, framework, lib)
@@ -185,14 +181,14 @@ class InstallQt(object):
             except:
                 libname = ''
             otoolProcess.stdout.close()
-            if otoolProcess.wait() == 1: # we found some Resource dir or similar -> skip
+            if otoolProcess.wait() == 1:  # we found some Resource dir or similar -> skip
                 continue
             frameworkpath, libpath = libname.split(frameworkname)
             if self.bundle:
                 newlibname = "@executable_path/../%s%s" % (frameworkname, libpath)
             else:
                 newlibname = "@executable_path/%s%s" % (frameworkname, libpath)
-            #print 'install_name_tool -id "%s" "%s"' % (newlibname, lib)
+            # print 'install_name_tool -id "%s" "%s"' % (newlibname, lib)
             os.system('install_name_tool -id "%s" "%s"' % (newlibname, lib))
 
             self.resolveDependancies(lib)
@@ -201,14 +197,11 @@ class InstallQt(object):
         otoolPipe = Popen('otool -L "%s"' % app, shell=True, stdout=PIPE).stdout
         otoolOutput = [line for line in otoolPipe]
         otoolPipe.close()
-        libs = [line.split()[0] for line in otoolOutput[1:] if ("Qt" in line
-                                                               or "phonon" in line)
-                                                               and not "@executable_path" in line]
-        frameworks = [lib[:lib.find(".framework")+len(".framework")] for lib in libs]
-        frameworks = [framework[framework.rfind('/')+1:] for framework in frameworks]
+        libs = [line.split()[0] for line in otoolOutput[1:] if ("Qt" in line or "phonon" in line) and "@executable_path" not in line]
+        frameworks = [lib[:lib.find(".framework") + len(".framework")] for lib in libs]
+        frameworks = [framework[framework.rfind('/') + 1:] for framework in frameworks]
         return zip(frameworks, libs)
 
-
     def changeDylPath(self, obj, framework, lib):
         newlibname = framework + lib.split(framework)[1]
         if self.bundle:
@@ -216,7 +209,7 @@ class InstallQt(object):
         else:
             newlibname = "@executable_path/Frameworks/%s" % newlibname
 
-        #print 'install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj)
+        # print 'install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj)
         os.system('install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj))
 
 if __name__ == "__main__":
index fe1ba87..f3b86da 100755 (executable)
@@ -27,7 +27,7 @@ if len(sys.argv) < 2:
 SOURCE_DIR = sys.argv[1]
 
 if len(sys.argv) < 4:
-    BUNDLE_NAME= "Quassel Client"
+    BUNDLE_NAME = "Quassel Client"
     EXE_NAME = "quasselclient"
 else:
     EXE_NAME = sys.argv[3]
@@ -38,9 +38,10 @@ if(os.path.dirname(EXE_NAME)):
     CONTENTS_DIR = os.path.dirname(EXE_NAME) + "/"
 CONTENTS_DIR += BUNDLE_NAME + ".app/Contents/"
 
-BUNDLE_VERSION = commands.getoutput("git --git-dir="+SOURCE_DIR+"/.git/ describe")
+BUNDLE_VERSION = commands.getoutput("git --git-dir=" + SOURCE_DIR + "/.git/ describe")
 ICON_FILE = "pics/quassel.icns"
 
+
 def createBundle():
     try:
         os.makedirs(CONTENTS_DIR + "MacOS")
@@ -48,23 +49,24 @@ def createBundle():
     except:
         pass
 
+
 def copyFiles(exeFile, iconFile):
     os.system("cp %s %sMacOs/%s" % (exeFile, CONTENTS_DIR.replace(' ', '\ '), BUNDLE_NAME.replace(' ', '\ ')))
     os.system("cp %s/%s %s/Resources" % (SOURCE_DIR, iconFile, CONTENTS_DIR.replace(' ', '\ ')))
 
+
 def createPlist(bundleName, iconFile, bundleVersion):
     templateFile = file(SOURCE_DIR + "/scripts/build/Info.plist", 'r')
     template = templateFile.read()
     templateFile.close()
 
     plistFile = file(CONTENTS_DIR + "Info.plist", 'w')
-    plistFile.write(template % {"BUNDLE_NAME" : bundleName,
-                                "ICON_FILE" : iconFile[iconFile.rfind("/")+1:],
-                                "BUNDLE_VERSION" : bundleVersion})
+    plistFile.write(template % {"BUNDLE_NAME": bundleName,
+                                "ICON_FILE": iconFile[iconFile.rfind("/") + 1:],
+                                "BUNDLE_VERSION": bundleVersion})
     plistFile.close()
 
 if __name__ == "__main__":
     createBundle()
     createPlist(BUNDLE_NAME, ICON_FILE, BUNDLE_VERSION)
     copyFiles(EXE_NAME, ICON_FILE)
-    pass
index 7ed231c..eeca2cf 100644 (file)
 #include "clientsettings.h"
 #include "peerfactory.h"
 
+#if QT_VERSION < 0x050000
+#    include "../../3rdparty/sha512/sha512.h"
+#endif
+
 using namespace Protocol;
 
 ClientAuthHandler::ClientAuthHandler(CoreAccount account, QObject *parent)
@@ -423,6 +427,7 @@ void ClientAuthHandler::checkAndEnableSsl(bool coreSupportsSsl)
             }
             s.setAccountValue("ShowNoCoreSslWarning", false);
             s.setAccountValue("SslCert", QString());
+            s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
         }
         if (_legacy)
             onConnectionReady();
@@ -444,6 +449,7 @@ void ClientAuthHandler::onSslSocketEncrypted()
         // That way, a warning will appear in case it becomes invalid at some point
         CoreAccountSettings s;
         s.setAccountValue("SSLCert", QString());
+        s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
     }
 
     emit encrypted(true);
@@ -462,8 +468,27 @@ void ClientAuthHandler::onSslErrors()
 
     CoreAccountSettings s;
     QByteArray knownDigest = s.accountValue("SslCert").toByteArray();
+    ClientAuthHandler::DigestVersion knownDigestVersion = static_cast<ClientAuthHandler::DigestVersion>(s.accountValue("SslCertDigestVersion").toInt());
+
+    QByteArray calculatedDigest;
+    switch (knownDigestVersion) {
+    case ClientAuthHandler::DigestVersion::Md5:
+        calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Md5);
+        break;
 
-    if (knownDigest != socket->peerCertificate().digest()) {
+    case ClientAuthHandler::DigestVersion::Sha2_512:
+#if QT_VERSION >= 0x050000
+        calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Sha512);
+#else
+        calculatedDigest = sha2_512(socket->peerCertificate().toDer());
+#endif
+        break;
+
+    default:
+        qWarning() << "Certificate digest version" << QString(knownDigestVersion) << "is not supported";
+    }
+    
+    if (knownDigest != calculatedDigest) {
         bool accepted = false;
         bool permanently = false;
         emit handleSslErrors(socket, &accepted, &permanently);
@@ -473,13 +498,42 @@ void ClientAuthHandler::onSslErrors()
             return;
         }
 
-        if (permanently)
-            s.setAccountValue("SslCert", socket->peerCertificate().digest());
-        else
+        if (permanently) {
+#if QT_VERSION >= 0x050000
+            s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512));
+#else
+            s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer()));
+#endif
+            s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest);
+        }
+        else {
             s.setAccountValue("SslCert", QString());
+            s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
+        }
+    }
+    else if (knownDigestVersion != ClientAuthHandler::DigestVersion::Latest) {
+#if QT_VERSION >= 0x050000
+        s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512));
+#else
+        s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer()));
+#endif
+        s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest);
     }
 
     socket->ignoreSslErrors();
 }
 
+#if QT_VERSION < 0x050000
+QByteArray ClientAuthHandler::sha2_512(const QByteArray &input) {
+    unsigned char output[64];
+    sha512((unsigned char*) input.constData(), input.size(), output, false);
+    // QByteArray::fromRawData() cannot be used here because that constructor
+    // does not copy "output" and the data is clobbered when the variable goes
+    // out of scope.
+    QByteArray result;
+    result.append((char*) output, 64);
+    return result;
+}
+#endif
+
 #endif /* HAVE_SSL */
index 7d6c935..00c2986 100644 (file)
@@ -36,6 +36,12 @@ class ClientAuthHandler : public AuthHandler
 public:
     ClientAuthHandler(CoreAccount account, QObject *parent = 0);
 
+    enum DigestVersion {
+        Md5,
+        Sha2_512,
+        Latest=Sha2_512
+    };
+
 public slots:
     void connectToCore();
 
@@ -83,6 +89,10 @@ private:
     void checkAndEnableSsl(bool coreSupportsSsl);
     void startRegistration();
 
+#if QT_VERSION < 0x050000
+    QByteArray sha2_512(const QByteArray &input);
+#endif
+
 private slots:
     void onSocketConnected();
     void onSocketStateChanged(QAbstractSocket::SocketState state);
index f599803..fd47bc0 100644 (file)
@@ -556,10 +556,9 @@ void TreeModel::endAppendChilds()
     ChildStatus cs = _childStatus;
 #ifndef QT_NO_DEBUG
     QModelIndex parent = indexByItem(parentItem);
-#endif
     Q_ASSERT(cs.parent == parent);
     Q_ASSERT(rowCount(parent) == cs.childCount + cs.end - cs.start + 1);
-
+#endif
     _aboutToRemoveOrInsert = false;
     for (int i = cs.start; i <= cs.end; i++) {
         connectItem(parentItem->child(i));
@@ -605,9 +604,9 @@ void TreeModel::endRemoveChilds()
 #ifndef QT_NO_DEBUG
     ChildStatus cs = _childStatus;
     QModelIndex parent = indexByItem(parentItem);
-#endif
     Q_ASSERT(cs.parent == parent);
     Q_ASSERT(rowCount(parent) == cs.childCount - cs.end + cs.start - 1);
+#endif
     _aboutToRemoveOrInsert = false;
 
     endRemoveRows();
index b13d3ee..a9dafcc 100644 (file)
@@ -103,13 +103,6 @@ int main(int argc, char **argv)
 # endif
 #endif
 
-    // Migrate settings from KDE4 to KF5 if appropriate
-#ifdef HAVE_KF5
-    Kdelibs4ConfigMigrator migrator(QCoreApplication::applicationName());
-    migrator.setConfigFiles(QStringList() << "quasselrc" << "quassel.notifyrc");
-    migrator.migrate();
-#endif
-
     AbstractCliParser *cliParser;
 
 #ifdef HAVE_KDE4
@@ -170,6 +163,8 @@ int main(int argc, char **argv)
     cliParser->addOption("oidentd-conffile", 0, "Set path to oidentd configuration file", "file");
 #ifdef HAVE_SSL
     cliParser->addSwitch("require-ssl", 0, "Require SSL for remote (non-loopback) client connections");
+    cliParser->addOption("ssl-cert", 0, "Specify the path to the SSL Certificate", "path", "configdir/quasselCert.pem");
+    cliParser->addOption("ssl-key", 0, "Specify the path to the SSL key", "path", "ssl-cert-path");
 #endif
     cliParser->addSwitch("enable-experimental-dcc", 0, "Enable highly experimental and unfinished support for CTCP DCC (DANGEROUS)");
 #endif
@@ -198,6 +193,13 @@ int main(int argc, char **argv)
     }
 #endif
 
+// Migrate settings from KDE4 to KF5 if appropriate
+#ifdef HAVE_KF5
+    Kdelibs4ConfigMigrator migrator(QCoreApplication::applicationName());
+    migrator.setConfigFiles(QStringList() << "quasselrc" << "quassel.notifyrc");
+    migrator.migrate();
+#endif
+
 #ifdef HAVE_KF5
     // FIXME: This should be done after loading the translation catalogue, but still in main()
     AboutData aboutData;
index 02eb3c0..79204b4 100644 (file)
@@ -22,6 +22,7 @@
 #define PEER_H
 
 #include <QAbstractSocket>
+#include <QDataStream>
 #include <QPointer>
 
 #include "authhandler.h"
index 92b32c5..e380924 100644 (file)
@@ -159,6 +159,7 @@ void CoreAuthHandler::handle(const RegisterClient &msg)
         useSsl = _connectionFeatures & Protocol::Encryption;
 
     if (Quassel::isOptionSet("require-ssl") && !useSsl && !_peer->isLocal()) {
+        quInfo() << qPrintable(tr("SSL required but non-SSL connection attempt from %1").arg(socket()->peerAddress().toString()));
         _peer->dispatch(ClientDenied(tr("<b>SSL is required!</b><br>You need to use SSL in order to connect to this core.")));
         _peer->close();
         return;
@@ -209,6 +210,7 @@ void CoreAuthHandler::handle(const Login &msg)
 
     UserId uid = Core::validateUser(msg.user, msg.password);
     if (uid == 0) {
+        quInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user));
         _peer->dispatch(LoginFailed(tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
         return;
     }
index 78495b2..29166c3 100644 (file)
@@ -37,7 +37,23 @@ SslServer::SslServer(QObject *parent)
     _isCertValid(false)
 {
     static bool sslWarningShown = false;
-    if (!setCertificate(Quassel::configDirPath() + "quasselCert.pem")) {
+
+    QString ssl_cert;
+    QString ssl_key;
+
+    if(Quassel::isOptionSet("ssl-cert")) {
+        ssl_cert = Quassel::optionValue("ssl-cert");
+    } else {
+        ssl_cert = Quassel::configDirPath() + "quasselCert.pem";
+    }
+
+    if(Quassel::isOptionSet("ssl-key")) {
+        ssl_key = Quassel::optionValue("ssl-key");
+    } else {
+        ssl_key = ssl_cert;
+    }
+
+    if (!setCertificate(ssl_cert, ssl_key)) {
         if (!sslWarningShown) {
             quWarning()
             << "SslServer: Unable to set certificate file\n"
@@ -79,7 +95,7 @@ void SslServer::incomingConnection(int socketDescriptor)
 }
 
 
-bool SslServer::setCertificate(const QString &path)
+bool SslServer::setCertificate(const QString &path, const QString &keyPath)
 {
     _isCertValid = false;
 
@@ -117,7 +133,27 @@ bool SslServer::setCertificate(const QString &path)
         return false;
     }
 
-    _key = QSslKey(&certFile, QSsl::Rsa);
+    // load key from keyPath if it differs from path, otherwise load key from path
+    if(path != keyPath) {
+        QFile keyFile(keyPath);
+        if(!keyFile.exists()) {
+            quWarning() << "SslServer: Key file" << qPrintable(keyPath) << "does not exist";
+            return false;
+        }
+
+        if (!keyFile.open(QIODevice::ReadOnly)) {
+            quWarning()
+            << "SslServer: Failed to open key file" << qPrintable(keyPath)
+            << "error:" << keyFile.error();
+            return false;
+        }
+
+        _key = QSslKey(&keyFile, QSsl::Rsa);
+        keyFile.close();
+    } else {
+        _key = QSslKey(&certFile, QSsl::Rsa);
+    }
+
     certFile.close();
 
     if (_cert.isNull()) {
@@ -142,7 +178,7 @@ bool SslServer::setCertificate(const QString &path)
             quWarning() << "SslServer: Certificate blacklisted";
     }
     if (_key.isNull()) {
-        quWarning() << "SslServer:" << qPrintable(path) << "contains no key data";
+        quWarning() << "SslServer:" << qPrintable(keyPath) << "contains no key data";
         return false;
     }
 
index bd72f29..9b69a8c 100644 (file)
@@ -49,7 +49,7 @@ protected:
     virtual void incomingConnection(int socketDescriptor);
 #endif
 
-    virtual bool setCertificate(const QString &path);
+    virtual bool setCertificate(const QString &path, const QString &keyPath);
 
 private:
     QLinkedList<QTcpSocket *> _pendingConnections;
index be9a14b..13279ba 100644 (file)
@@ -130,7 +130,7 @@ if (QT_QTDBUS_FOUND OR Qt5DBus_FOUND)
     qt_add_dbus_adaptor  (SOURCES ../../interfaces/org.kde.StatusNotifierItem.xml statusnotifieritemdbus.h StatusNotifierItemDBus)
 endif()
 
-if (QT_QTWEBKIT_FOUND OR Qt5WebKitWidgets_FOUND)
+if (HAVE_WEBKIT)
     add_definitions(-DHAVE_WEBKIT)
     list(APPEND QT_MODULES WebKit)
     if (USE_QT5)