aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik aheinecke@404: * Software engineering by Intevation GmbH aheinecke@404: * aheinecke@404: * This file is Free Software under the GNU GPL (v>=2) aheinecke@404: * and comes with ABSOLUTELY NO WARRANTY! aheinecke@404: * See LICENSE.txt for details. aheinecke@404: */ aheinecke@10: #include "downloader.h" aheinecke@10: aheinecke@10: #ifndef DOWNLOAD_SERVER andre@1387: #define DOWNLOAD_SERVER "https://updates.trustbridge.de" aheinecke@10: #endif aheinecke@10: aheinecke@10: #include aheinecke@15: #include aheinecke@10: #include aheinecke@15: #include andre@32: #include andre@32: #include andre@956: #include andre@27: andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@990: #include andre@27: andre@808: #define MAX_SW_SIZE 15728640 andre@27: #define MAX_LIST_SIZE 1048576 andre@32: andre@924: #ifdef USE_CURL andre@908: #include "sslconnection_curl.h" andre@924: #else andre@908: #include "sslconnection_bare.h" andre@924: #endif aheinecke@10: andre@990: static int accept_ciphers[] = { andre@990: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, andre@990: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, andre@990: TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, andre@990: 0 andre@990: }; andre@990: aheinecke@15: Downloader::Downloader(QObject* parent, const QString& url, aheinecke@15: const QByteArray& certificate, aheinecke@15: const QDateTime& newestSW, aheinecke@45: const QDateTime& newestList, aheinecke@45: const QString& resourceSW, rrenkert@460: const QString& resourceList, rrenkert@460: bool downloadSW): aheinecke@12: QThread(parent), aheinecke@15: mLastModSW(newestSW), andre@27: mLastModList(newestList), aheinecke@45: mResourceSW(resourceSW), aheinecke@45: mResourceList(resourceList), andre@908: mDownloadSW(downloadSW) aheinecke@10: { andre@908: #ifdef USE_CURL andre@908: mSSLConnection = new SSLConnectionCurl(url, certificate); andre@956: /* Set up Proxy support. */ andre@956: QSettings settings; andre@956: QString settingsProxy = settings.value("ProxyURL").toString(); andre@1062: bool useProxy = settings.value("UseProxy", false).toBool(); andre@1062: if (useProxy && settingsProxy.isEmpty()) { andre@956: QByteArray envProxy = qgetenv("http_proxy"); andre@956: if (envProxy.size()) { andre@956: settingsProxy = QString::fromLocal8Bit(envProxy); andre@956: } andre@956: } andre@1062: if (useProxy && !settingsProxy.isEmpty()) { andre@956: mSSLConnection->setProxy(QUrl(settingsProxy)); andre@956: } andre@908: #else andre@908: mSSLConnection = new SSLConnectionBare(url, certificate); andre@908: #endif andre@990: setCiphersuites(accept_ciphers); andre@27: } andre@27: andre@27: Downloader::~Downloader() { andre@908: delete mSSLConnection; aheinecke@10: } aheinecke@10: andre@990: void Downloader::setCiphersuites(int suites[]) { andre@990: mSSLConnection->setCiphersuites(suites); andre@990: } andre@990: aheinecke@15: QString Downloader::getDataDirectory() aheinecke@10: { aheinecke@15: QString candidate = aheinecke@15: QStandardPaths::writableLocation(QStandardPaths::DataLocation); aheinecke@12: aheinecke@15: if (candidate.isEmpty()) { aheinecke@15: qDebug() << "Could not find writeable locaction for me"; aheinecke@15: return QString(); aheinecke@15: } aheinecke@15: aheinecke@15: QDir cDir(candidate); aheinecke@15: aheinecke@15: if (!cDir.exists()) { aheinecke@15: if (!cDir.mkpath(candidate)) { aheinecke@15: qDebug() << "Could not create path to: " << candidate; aheinecke@15: return QString(); aheinecke@15: } aheinecke@15: } aheinecke@15: return cDir.absolutePath(); aheinecke@10: } andre@27: andre@27: andre@27: void Downloader::run() { andre@27: int ret; andre@32: QDateTime remoteModList; andre@32: QDateTime remoteModSW; andre@27: andre@908: if (!mSSLConnection->initialized()) { aheinecke@45: emit error(tr("Failed to initialize SSL Module."), SSLConnection::ErrUnknown); andre@27: return; andre@27: } andre@27: andre@908: ret = mSSLConnection->connect(); andre@32: andre@27: if (ret != 0) { aheinecke@45: emit error(tr("Failed to connect."), andre@908: mSSLConnection->getLastError()); andre@27: return; andre@27: } andre@27: andre@27: emit progress(tr("Connected"), 1, -1); andre@27: andre@910: remoteModSW = mSSLConnection->getLastModifiedHeader(mResourceSW); rrenkert@485: emit lastModifiedDate(remoteModSW); andre@32: aheinecke@459: if (!remoteModSW.isValid()) { andre@910: emit error (tr("Connection failed."), SSLConnection::InvalidResponse); aheinecke@459: qDebug() << "Could not parse headers for Software"; andre@32: return; andre@32: } andre@32: andre@32: if (!mLastModSW.isValid() || remoteModSW > mLastModSW) { andre@32: QString dataDirectory = getDataDirectory(); andre@32: andre@32: if (dataDirectory.isEmpty()) { andre@32: qDebug() << "Failed to get data directory"; andre@32: return; andre@32: } andre@32: andre@32: QString fileName = dataDirectory.append("/SW-") aheinecke@442: .append(remoteModSW.toString("yyyyMMddHHmmss")) andre@809: #ifdef WIN32 andre@32: .append(".exe"); andre@809: #else andre@809: .append(".sh"); andre@809: #endif andre@32: andre@32: qDebug() << "fileName: " << fileName; andre@32: rrenkert@460: if (mDownloadSW) { andre@910: if (!mSSLConnection->downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) { andre@1227: emit error(tr("Failed to download File.") + "\n" andre@1227: + tr("The connection to the update server was lost or" andre@1227: " the disk is full."), SSLConnection::ConnectionLost); andre@809: qDebug() << "Failed to download software update."; rrenkert@460: return; rrenkert@460: } andre@809: QFile::setPermissions(fileName, QFileDevice::ReadOwner | andre@809: QFileDevice::WriteOwner | andre@809: QFileDevice::ExeOwner); andre@32: } andre@32: andre@32: emit newSoftwareAvailable(fileName, remoteModSW); aheinecke@458: return; aheinecke@458: } aheinecke@458: andre@910: remoteModList = mSSLConnection->getLastModifiedHeader(mResourceList); aheinecke@459: if (!remoteModList.isValid()) { andre@910: emit error (tr("Connection failed."), SSLConnection::InvalidResponse); aheinecke@459: qDebug() << "Could not parse headers for List"; aheinecke@459: return; aheinecke@459: } aheinecke@458: aheinecke@458: if (!mLastModList.isValid() || remoteModList > mLastModList) { andre@32: QString dataDirectory = getDataDirectory(); andre@32: andre@32: if (dataDirectory.isEmpty()) { andre@32: qDebug() << "Failed to get data directory"; andre@32: return; andre@32: } andre@32: andre@32: QString fileName = dataDirectory.append("/list-") rrenkert@443: .append(remoteModList.toString("yyyyMMddHHmmss")) andre@32: .append(".txt"); andre@32: andre@32: qDebug() << "fileName: " << fileName; andre@32: andre@910: if (!mSSLConnection->downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) { andre@32: return; andre@32: } andre@32: andre@32: emit newListAvailable(fileName, remoteModList); andre@32: } andre@27: andre@27: emit progress(tr("Closing"), 1, -1); andre@27: }