From: Manuel Nickschas Date: Thu, 8 Oct 2015 21:33:54 +0000 (+0200) Subject: Merge pull request #133 from mamarley/clientreconnectfix X-Git-Tag: travis-deploy-test~559 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=d98cc721477645abcb5387313f3ad2c96a580ad6;hp=7af835c93948efa6a2160f7516b9f3296590a22f Merge pull request #133 from mamarley/clientreconnectfix Keep _wantReconnect set to true by default instead of false --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a15aef74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build* +*.pyc +tags diff --git a/CMakeLists.txt b/CMakeLists.txt index d8739738..1a22fac9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/scripts/build/macosx_DeployApp.py b/scripts/build/macosx_DeployApp.py index c1cddf55..e6cfc1d1 100755 --- a/scripts/build/macosx_DeployApp.py +++ b/scripts/build/macosx_DeployApp.py @@ -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__": diff --git a/scripts/build/macosx_makebundle.py b/scripts/build/macosx_makebundle.py index fe1ba87c..f3b86da4 100755 --- a/scripts/build/macosx_makebundle.py +++ b/scripts/build/macosx_makebundle.py @@ -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 diff --git a/src/client/clientauthhandler.cpp b/src/client/clientauthhandler.cpp index 7ed231c2..eeca2cff 100644 --- a/src/client/clientauthhandler.cpp +++ b/src/client/clientauthhandler.cpp @@ -34,6 +34,10 @@ #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(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 */ diff --git a/src/client/clientauthhandler.h b/src/client/clientauthhandler.h index 7d6c9357..00c2986e 100644 --- a/src/client/clientauthhandler.h +++ b/src/client/clientauthhandler.h @@ -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); diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index f599803d..fd47bc04 100644 --- a/src/client/treemodel.cpp +++ b/src/client/treemodel.cpp @@ -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(); diff --git a/src/common/main.cpp b/src/common/main.cpp index b13d3eef..a9dafccd 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -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; diff --git a/src/common/peer.h b/src/common/peer.h index 02eb3c0c..79204b4f 100644 --- a/src/common/peer.h +++ b/src/common/peer.h @@ -22,6 +22,7 @@ #define PEER_H #include +#include #include #include "authhandler.h" diff --git a/src/core/coreauthhandler.cpp b/src/core/coreauthhandler.cpp index 92b32c5c..e3809246 100644 --- a/src/core/coreauthhandler.cpp +++ b/src/core/coreauthhandler.cpp @@ -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("SSL is required!
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("Invalid username or password!
The username/password combination you supplied could not be found in the database."))); return; } diff --git a/src/core/sslserver.cpp b/src/core/sslserver.cpp index 78495b27..29166c35 100644 --- a/src/core/sslserver.cpp +++ b/src/core/sslserver.cpp @@ -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; } diff --git a/src/core/sslserver.h b/src/core/sslserver.h index bd72f29b..9b69a8c5 100644 --- a/src/core/sslserver.h +++ b/src/core/sslserver.h @@ -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 _pendingConnections; diff --git a/src/qtui/CMakeLists.txt b/src/qtui/CMakeLists.txt index be9a14b5..13279baa 100644 --- a/src/qtui/CMakeLists.txt +++ b/src/qtui/CMakeLists.txt @@ -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)