view ui/downloader.cpp @ 1395:a2574a029322

Fix Base 64 signature size calculation. If the signature byte size is not equally dividable by three the base 64 encoding needs three additional bytes. The value is now fixed to avoid such errors in the future.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 26 Jan 2015 13:17:32 +0100
parents c64b6c56ce96
children
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://updates.trustbridge.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.") + "\n"
                        + tr("The connection to the update server was lost or"
                            " the disk is full."), 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/