view ui/downloader.cpp @ 1075:7e1fd6d96714

(issue109) Feedback improved. Shell translation updated.
author Bernhard Reiter <bernhard@intevation.de>
date Thu, 11 Sep 2014 10:18:46 +0200
parents 515345358b71
children 508c96e72f62
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (v>=2)
 * and comes with ABSOLUTELY NO WARRANTY!
 * See LICENSE.txt for details.
 */
#include "downloader.h"

#ifndef DOWNLOAD_SERVER
#define DOWNLOAD_SERVER "https://www.intevation.de"
#endif

#include <QFile>
#include <QDir>
#include <QDebug>
#include <QStandardPaths>
#include <QLocale>
#include <QSaveFile>
#include <QSettings>

#include <polarssl/net.h>
#include <polarssl/ssl.h>
#include <polarssl/entropy.h>
#include <polarssl/ctr_drbg.h>
#include <polarssl/error.h>
#include <polarssl/certs.h>
#include <polarssl/ssl_ciphersuites.h>

#define MAX_SW_SIZE 15728640
#define MAX_LIST_SIZE 1048576

#ifdef USE_CURL
#include "sslconnection_curl.h"
#else
#include "sslconnection_bare.h"
#endif

#ifdef RELEASE_BUILD
static int accept_ciphers[] = {
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
    TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
    0
};
#else
static int accept_ciphers[] = {
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
    TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
    TLS_RSA_WITH_AES_256_CBC_SHA,
    0
};
#endif

Downloader::Downloader(QObject* parent, const QString& url,
                       const QByteArray& certificate,
                       const QDateTime& newestSW,
                       const QDateTime& newestList,
                       const QString& resourceSW,
                       const QString& resourceList,
                       bool downloadSW):
    QThread(parent),
    mLastModSW(newestSW),
    mLastModList(newestList),
    mResourceSW(resourceSW),
    mResourceList(resourceList),
    mDownloadSW(downloadSW)
{
#ifdef USE_CURL
    mSSLConnection = new SSLConnectionCurl(url, certificate);
/* Set up Proxy support. */
    QSettings settings;
    QString settingsProxy = settings.value("ProxyURL").toString();
    bool useProxy = settings.value("UseProxy", false).toBool();
    if (useProxy && settingsProxy.isEmpty()) {
        QByteArray envProxy = qgetenv("http_proxy");
        if (envProxy.size()) {
            settingsProxy = QString::fromLocal8Bit(envProxy);
        }
    }
    if (useProxy && !settingsProxy.isEmpty()) {
        mSSLConnection->setProxy(QUrl(settingsProxy));
    }
#else
    mSSLConnection = new SSLConnectionBare(url, certificate);
#endif
    setCiphersuites(accept_ciphers);
}

Downloader::~Downloader() {
    delete mSSLConnection;
}

void Downloader::setCiphersuites(int suites[]) {
    mSSLConnection->setCiphersuites(suites);
}

QString Downloader::getDataDirectory()
{
    QString candidate =
        QStandardPaths::writableLocation(QStandardPaths::DataLocation);

    if (candidate.isEmpty()) {
        qDebug() << "Could not find writeable locaction for me";
        return QString();
    }

    QDir cDir(candidate);

    if (!cDir.exists()) {
        if (!cDir.mkpath(candidate)) {
            qDebug() << "Could not create path to: " << candidate;
            return QString();
        }
    }
    return cDir.absolutePath();
}


void Downloader::run() {
    int ret;
    QDateTime remoteModList;
    QDateTime remoteModSW;

    if (!mSSLConnection->initialized()) {
        emit error(tr("Failed to initialize SSL Module."), SSLConnection::ErrUnknown);
        return;
    }

    ret = mSSLConnection->connect();

    if (ret != 0) {
        emit error(tr("Failed to connect."),
                   mSSLConnection->getLastError());
        return;
    }

    emit progress(tr("Connected"), 1, -1);

    remoteModSW = mSSLConnection->getLastModifiedHeader(mResourceSW);
    emit lastModifiedDate(remoteModSW);

    if (!remoteModSW.isValid()) {
        emit error (tr("Connection failed."), SSLConnection::InvalidResponse);
        qDebug() << "Could not parse headers for Software";
        return;
    }

    if (!mLastModSW.isValid() || remoteModSW > mLastModSW) {
        QString dataDirectory = getDataDirectory();

        if (dataDirectory.isEmpty()) {
            qDebug() << "Failed to get data directory";
            return;
        }

        QString fileName = dataDirectory.append("/SW-")
            .append(remoteModSW.toString("yyyyMMddHHmmss"))
#ifdef WIN32
            .append(".exe");
#else
            .append(".sh");
#endif

        qDebug() << "fileName: " << fileName;

        if (mDownloadSW) {
            if (!mSSLConnection->downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) {
                emit error(tr("Failed to download File"), SSLConnection::ConnectionLost);
                qDebug() << "Failed to download software update.";
                return;
            }
            QFile::setPermissions(fileName, QFileDevice::ReadOwner |
                                            QFileDevice::WriteOwner |
                                            QFileDevice::ExeOwner);
        }

        emit newSoftwareAvailable(fileName, remoteModSW);
        return;
    }

    remoteModList = mSSLConnection->getLastModifiedHeader(mResourceList);
    if (!remoteModList.isValid()) {
        emit error (tr("Connection failed."), SSLConnection::InvalidResponse);
        qDebug() << "Could not parse headers for List";
        return;
    }

    if (!mLastModList.isValid() || remoteModList > mLastModList) {
        QString dataDirectory = getDataDirectory();

        if (dataDirectory.isEmpty()) {
            qDebug() << "Failed to get data directory";
            return;
        }

        QString fileName = dataDirectory.append("/list-")
            .append(remoteModList.toString("yyyyMMddHHmmss"))
            .append(".txt");

        qDebug() << "fileName: " << fileName;

        if (!mSSLConnection->downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) {
            return;
        }

        emit newListAvailable(fileName, remoteModList);
    }

    emit progress(tr("Closing"), 1, -1);
}

http://wald.intevation.org/projects/trustbridge/