view ui/downloader.cpp @ 1119:5349e2354c48

(issue54) Merge branch runafterinstall There is now an NSIS Plugin that executes the Software after installation using COM in the shell of the current user. With the way over the shell there is no inheritance / token management required. As it is impossible to drop all privileges of a token granted by UAC and still be able to reelevate the Token again with another RunAs call later this round trip over the Shell was necessary.
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 16 Sep 2014 19:48:22 +0200
parents 508c96e72f62
children a1e990947172
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://tb-devel.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

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
};

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/