1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Merge branch 'autoupdate'

This commit is contained in:
Tux3 / Mlkj / !Lev.uXFMLA 2014-11-10 00:34:33 +01:00
commit 55939e9563
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
36 changed files with 2345 additions and 8 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@ Makefile
qtox qtox
*.qm *.qm
*.orig *.orig
build-*-Release
build-*-Debug

View File

@ -57,7 +57,7 @@ contains(JENKINS,YES) {
# Rules for Windows, Mac OSX, and Linux # Rules for Windows, Mac OSX, and Linux
win32 { win32 {
RC_FILE = windows/qtox.rc RC_FILE = windows/qtox.rc
LIBS += -liphlpapi -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread LIBS += -liphlpapi -L$$PWD/libs/lib -lsodium -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32 LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32
} else { } else {
@ -76,7 +76,7 @@ win32 {
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0 LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
} else { } else {
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
} }
contains(JENKINS, YES) { contains(JENKINS, YES) {
@ -146,7 +146,9 @@ HEADERS += src/widget/form/addfriendform.h \
src/ipc.h \ src/ipc.h \
src/widget/toxuri.h \ src/widget/toxuri.h \
src/toxdns.h \ src/toxdns.h \
src/widget/toxsave.h src/widget/toxsave.h \
src/autoupdate.h \
src/misc/serialize.h
SOURCES += \ SOURCES += \
src/widget/form/addfriendform.cpp \ src/widget/form/addfriendform.cpp \
@ -209,4 +211,6 @@ SOURCES += \
src/widget/toxuri.cpp \ src/widget/toxuri.cpp \
src/toxdns.cpp \ src/toxdns.cpp \
src/ipc.cpp \ src/ipc.cpp \
src/widget/toxsave.cpp src/widget/toxsave.cpp \
src/autoupdate.cpp \
src/misc/serialize.cpp

414
src/autoupdate.cpp Normal file
View File

@ -0,0 +1,414 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "src/autoupdate.h"
#include "src/misc/serialize.h"
#include "src/misc/settings.h"
#include "src/widget/widget.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QProcess>
#include <QtConcurrent/QtConcurrent>
#include <QMessageBox>
#ifdef Q_OS_WIN
#include <windows.h>
#include <shellapi.h>
#endif
#ifdef Q_OS_WIN
const QString AutoUpdater::platform = "win32";
const QString AutoUpdater::updaterBin = "qtox-updater.exe";
#else
const QString AutoUpdater::platform;
const QString AutoUpdater::updaterBin;
#endif
const QString AutoUpdater::updateServer = "http://mlkj.bounceme.net";
const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/version";
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
{
0xa5, 0x80, 0xf3, 0xb7, 0xd0, 0x10, 0xc0, 0xf9, 0xd6, 0xcf, 0x48, 0x15, 0x99, 0x70, 0x92, 0x49,
0xf6, 0xe8, 0xe5, 0xe2, 0x6c, 0x73, 0x8c, 0x48, 0x25, 0xed, 0x01, 0x72, 0xf7, 0x6c, 0x17, 0x28
};
bool AutoUpdater::isUpdateAvailable()
{
QString newVersion = getUpdateVersion();
if (newVersion.isEmpty() || newVersion == GIT_VERSION)
return false;
else
return true;
}
QString AutoUpdater::getUpdateVersion()
{
QString version;
// Updates only for supported platforms
if (platform.isEmpty())
return version;
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI)));
while (!reply->isFinished())
qApp->processEvents();
if (reply->error() != QNetworkReply::NoError)
{
qWarning() << "AutoUpdater: getUpdateVersion: network error: "<<reply->errorString();
reply->deleteLater();
manager->deleteLater();
return version;
}
QByteArray data = reply->readAll();
reply->deleteLater();
manager->deleteLater();
if (data.size() < (int)(1+crypto_sign_BYTES))
return version;
// Check updater protocol version
if ((int)data[0] != '1')
{
qWarning() << "AutoUpdater: getUpdateVersion: Bad version "<<(uint8_t)data[0];
return version;
}
// Check the signature
QByteArray sigData = data.mid(1, crypto_sign_BYTES);
unsigned char* sig = (unsigned char*)sigData.data();
QByteArray msgData = data.mid(1+crypto_sign_BYTES);
unsigned char* msg = (unsigned char*)msgData.data();
if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0)
{
qCritical() << "AutoUpdater: getUpdateVersion: RECEIVED FORGED VERSION FILE FROM "<<updateServer;
return version;
}
version = msgData;
return version;
}
QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData)
{
QList<UpdateFileMeta> flist;
if (flistData.isEmpty())
{
qWarning() << "AutoUpdater::parseflist: Empty data";
return flist;
}
// Check version
if (flistData[0] != '1')
{
qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0];
return flist;
}
flistData = flistData.mid(1);
// Check signature
if (flistData.size() < (int)(crypto_sign_BYTES))
{
qWarning() << "AutoUpdater::parseflist: Truncated data";
return flist;
}
else
{
QByteArray msgData = flistData.mid(crypto_sign_BYTES);
unsigned char* msg = (unsigned char*)msgData.data();
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0)
{
qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE";
return flist;
}
flistData = flistData.mid(crypto_sign_BYTES);
}
// Parse. We assume no errors handling needed since the signature is valid.
while (!flistData.isEmpty())
{
UpdateFileMeta newFile;
memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES);
flistData = flistData.mid(crypto_sign_BYTES);
newFile.id = dataToString(flistData);
flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData));
newFile.installpath = dataToString(flistData);
flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData));
newFile.size = dataToUint64(flistData);
flistData = flistData.mid(8);
flist += newFile;
}
return flist;
}
QByteArray AutoUpdater::getUpdateFlist()
{
QByteArray flist;
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI)));
while (!reply->isFinished())
qApp->processEvents();
if (reply->error() != QNetworkReply::NoError)
{
qWarning() << "AutoUpdater: getUpdateFlist: network error: "<<reply->errorString();
reply->deleteLater();
manager->deleteLater();
return flist;
}
flist = reply->readAll();
reply->deleteLater();
manager->deleteLater();
return flist;
}
QByteArray AutoUpdater::getLocalFlist()
{
QByteArray flist;
QFile flistFile("flist");
if (!flistFile.open(QIODevice::ReadOnly))
{
qWarning() << "AutoUpdater::getLocalFlist: Can't open local flist";
return flist;
}
flist = flistFile.readAll();
flistFile.close();
return flist;
}
QList<AutoUpdater::UpdateFileMeta> AutoUpdater::genUpdateDiff(QList<UpdateFileMeta> updateFlist)
{
QList<UpdateFileMeta> diff;
QList<UpdateFileMeta> localFlist = parseFlist(getLocalFlist());
for (UpdateFileMeta file : updateFlist)
if (!localFlist.contains(file))
diff += file;
return diff;
}
AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta)
{
UpdateFile file;
file.metadata = fileMeta;
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI+fileMeta.id)));
while (!reply->isFinished())
qApp->processEvents();
if (reply->error() != QNetworkReply::NoError)
{
qWarning() << "AutoUpdater: getUpdateFile: network error: "<<reply->errorString();
reply->deleteLater();
manager->deleteLater();
return file;
}
file.data = reply->readAll();
reply->deleteLater();
manager->deleteLater();
return file;
}
bool AutoUpdater::downloadUpdate()
{
// Updates only for supported platforms
if (platform.isEmpty())
return false;
// Get a list of files to update
QByteArray newFlistData = getUpdateFlist();
QList<UpdateFileMeta> newFlist = parseFlist(newFlistData);
QList<UpdateFileMeta> diff = genUpdateDiff(newFlist);
qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files";
// Create an empty directory to download updates into
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
QDir updateDir(updateDirStr);
if (updateDir.exists())
updateDir.removeRecursively();
QDir().mkdir(updateDirStr);
updateDir = QDir(updateDirStr);
if (!updateDir.exists())
{
qWarning() << "AutoUpdater::downloadUpdate: Can't create update directory, aborting...";
return false;
}
// Write the new flist for the updater
QFile newFlistFile(updateDirStr+"flist");
if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
qWarning() << "AutoUpdater::downloadUpdate: Can't save new flist file, aborting...";
return false;
}
newFlistFile.write(newFlistData);
newFlistFile.close();
// Download and write each new file
for (UpdateFileMeta fileMeta : diff)
{
qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ...";
// Create subdirs if necessary
QString fileDirStr{QFileInfo(updateDirStr+fileMeta.installpath).absolutePath()};
if (!QDir(fileDirStr).exists())
QDir().mkpath(fileDirStr);
// Download
UpdateFile file = getUpdateFile(fileMeta);
if (file.data.isNull())
{
qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting...";
return false;
}
// Check signature
if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(),
file.data.size(), key) != 0)
{
qCritical() << "AutoUpdater: downloadUpdate: RECEIVED FORGED FILE, aborting...";
return false;
}
// Save
QFile fileFile(updateDirStr+fileMeta.installpath);
if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
qWarning() << "AutoUpdater::downloadUpdate: Can't save new update file, aborting...";
return false;
}
fileFile.write(file.data);
fileFile.close();
}
return true;
}
bool AutoUpdater::isLocalUpdateReady()
{
// Updates only for supported platforms
if (platform.isEmpty())
return false;
// Check that there's an update dir in the first place, valid or not
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
QDir updateDir(updateDirStr);
if (!updateDir.exists())
return false;
// Check that we have a flist and that every file on the diff exists
QFile updateFlistFile(updateDirStr+"flist");
if (!updateFlistFile.open(QIODevice::ReadOnly))
return false;
QByteArray updateFlistData = updateFlistFile.readAll();
updateFlistFile.close();
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
for (UpdateFileMeta fileMeta : diff)
if (!QFile::exists(updateDirStr+fileMeta.installpath))
return false;
return true;
}
void AutoUpdater::installLocalUpdate()
{
qDebug() << "AutoUpdater: About to start the qTox updater to install a local update";
// Delete the update if we fail so we don't fail again.
// Updates only for supported platforms.
if (platform.isEmpty())
{
qCritical() << "AutoUpdater: Failed to start the qTox updater, removing the update and exiting";
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
QDir(updateDirStr).removeRecursively();
exit(-1);
}
// Workaround QTBUG-7645
// QProcess fails silently when elevation is required instead of showing a UAC prompt on Win7/Vista
#ifdef Q_OS_WIN
int result = (int)::ShellExecuteA(0, "open", updaterBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);
if (SE_ERR_ACCESSDENIED == result)
{
// Requesting elevation
result = (int)::ShellExecuteA(0, "runas", updaterBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);
}
if (result <= 32)
{
goto fail;
}
#else
if (!QProcess::startDetached(updaterBin))
goto fail;
#endif
exit(0);
// Centralized error handling
fail:
qCritical() << "AutoUpdater: Failed to start the qTox updater, removing the update and exiting";
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
QDir(updateDirStr).removeRecursively();
exit(-1);
}
void AutoUpdater::checkUpdatesAsyncInteractive()
{
QtConcurrent::run(&AutoUpdater::checkUpdatesAsyncInteractiveWorker);
}
void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
{
if (!isUpdateAvailable())
return;
if (Widget::getInstance()->askMsgboxQuestion(QObject::tr("Update", "The title of a message box"),
QObject::tr("An update is available, do you want to download it now ?\nIt will be installed when qTox restarts.")))
{
downloadUpdate();
}
}

115
src/autoupdate.h Normal file
View File

@ -0,0 +1,115 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef AUTOUPDATE_H
#define AUTOUPDATE_H
#include <QString>
#include <QList>
#include <sodium.h>
/// For now we only support auto updates on Windows, although extending it is not a technical issue.
/// Linux and Mac users are expected to use their package managers or update manually through official channels.
#ifdef Q_OS_WIN
#define AUTOUPDATE_ENABLED 1
#else
#define AUTOUPDATE_ENABLED 0
#endif
/// Handles checking and applying updates for qTox
/// Do *NOT* use auto update unless AUTOUPDATE_ENABLED is defined to 1
class AutoUpdater
{
public:
struct UpdateFileMeta
{
unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519)
QString id; ///< Unique id of the file
QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute
uint64_t size; ///< Size in bytes of the file
bool operator==(const UpdateFileMeta& other)
{
return (size == other.size
&& id == other.id && installpath == other.installpath
&& memcmp(sig, other.sig, crypto_sign_BYTES) == 0);
}
};
struct UpdateFile
{
UpdateFileMeta metadata;
QByteArray data;
};
public:
/// Connects to the qTox update server, if an updat is found shows a dialog to the user asking to download it
/// Runs asynchronously in its own thread, and will return immediatly
/// Will call isUpdateAvailable, and as such may processEvents
static void checkUpdatesAsyncInteractive();
/// Connects to the qTox update server, returns true if an update is available for download
/// Will call getUpdateVersion, and as such may block and processEvents
static bool isUpdateAvailable();
/// Fetch the version string of the last update available from the qTox update server
/// Will try to follow qTox's proxy settings, may block and processEvents
static QString getUpdateVersion();
/// Will try to download an update, if successful returns true and qTox will apply it after a restart
/// Will try to follow qTox's proxy settings, may block and processEvents
static bool downloadUpdate();
/// Returns true if an update is downloaded and ready to be installed
/// If so, call installLocalUpdate. If not, call downloadUpdate.
/// This only checks that we downloaded an update and didn't stop in the middle, not that every file is still valid
static bool isLocalUpdateReady();
/// Launches the qTox updater to try to install the local update and exits immediately
/// Will not check that the update actually exists, use isLocalUpdateReady first for that
/// The qTox updater will restart us after the update is done
/// Note: If we fail to start the qTox updater, we will delete the update and exit
[[ noreturn ]] static void installLocalUpdate();
protected:
/// Parses and validates a flist file. Returns an empty list on error
static QList<UpdateFileMeta> parseFlist(QByteArray flistData);
/// Gets the update server's flist. Returns an empty array on error
/// Will try to follow qTox's proxy settings, may block and processEvents
static QByteArray getUpdateFlist();
/// Gets the local flist. Returns an empty array on error
static QByteArray getLocalFlist();
/// Generates a list of files we need to update
static QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist);
/// Tries to fetch the file from the update server. Returns a file with a null QByteArray on error.
/// Note that a file with an empty but non-null QByteArray is not an error, merely a file of size 0.
/// Will try to follow qTox's proxy settings, may block and processEvents
static UpdateFile getUpdateFile(UpdateFileMeta fileMeta);
/// Does the actual work for checkUpdatesAsyncInteractive
/// Blocking, but otherwise has the same properties than checkUpdatesAsyncInteractive
static void checkUpdatesAsyncInteractiveWorker();
private:
AutoUpdater() = delete;
private:
// Constants
static const QString updateServer; ///< Hostname of the qTox update server
static const QString platform; ///< Name of platform we're trying to get updates for
static const QString checkURI; ///< URI of the file containing the latest version string
static const QString flistURI; ///< URI of the file containing info on each file (hash, signature, size, name, ..)
static const QString filesURI; ///< URI of the actual files of the latest version
static const QString updaterBin; ///< Path to the qtox-updater binary
static unsigned char key[];
};
#endif // AUTOUPDATE_H

View File

@ -19,6 +19,7 @@
#include "src/ipc.h" #include "src/ipc.h"
#include "src/widget/toxuri.h" #include "src/widget/toxuri.h"
#include "src/widget/toxsave.h" #include "src/widget/toxsave.h"
#include "src/autoupdate.h"
#include <QApplication> #include <QApplication>
#include <QFontDatabase> #include <QFontDatabase>
#include <QDebug> #include <QDebug>
@ -27,6 +28,8 @@
#include <QDateTime> #include <QDateTime>
#include <QMutexLocker> #include <QMutexLocker>
#include <sodium.h>
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
static QtMessageHandler dflt; static QtMessageHandler dflt;
static QTextStream* logFile {nullptr}; static QTextStream* logFile {nullptr};
@ -55,6 +58,8 @@ int main(int argc, char *argv[])
a.setApplicationName("qTox"); a.setApplicationName("qTox");
a.setOrganizationName("Tox"); a.setOrganizationName("Tox");
sodium_init(); // For the auto-updater
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
logFile = new QTextStream; logFile = new QTextStream;
dflt = qInstallMessageHandler(nullptr); dflt = qInstallMessageHandler(nullptr);
@ -83,6 +88,12 @@ int main(int argc, char *argv[])
// Install Unicode 6.1 supporting font // Install Unicode 6.1 supporting font
QFontDatabase::addApplicationFont("://DejaVuSans.ttf"); QFontDatabase::addApplicationFont("://DejaVuSans.ttf");
// Check whether we have an update waiting to be installed
#if AUTOUPDATE_ENABLED
if (AutoUpdater::isLocalUpdateReady())
AutoUpdater::installLocalUpdate(); ///< NORETURN
#endif
// Inter-process communication // Inter-process communication
IPC ipc; IPC ipc;
ipc.registerEventHandler(&toxURIEventHandler); ipc.registerEventHandler(&toxURIEventHandler);

254
src/misc/serialize.cpp Normal file
View File

@ -0,0 +1,254 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "src/misc/serialize.h"
QByteArray doubleToData(double num)
{
union
{
char tab[8];
double n;
} castUnion;
//char n[8];
//*((double*) n) = num;
castUnion.n=num;
return QByteArray(castUnion.tab,8);
}
QByteArray floatToData(float num)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.n=num;
return QByteArray(castUnion.tab,4);
}
float dataToFloat(QByteArray data)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.tab[0]=data.data()[0];
castUnion.tab[1]=data.data()[1];
castUnion.tab[2]=data.data()[2];
castUnion.tab[3]=data.data()[3];
return castUnion.n;
}
// Converts a string into PNet string data
QByteArray stringToData(QString str)
{
QByteArray data(4,0);
// Write the size in a Uint of variable lenght (8-32 bits)
int i=0;
uint num1 = (uint)str.toUtf8().size();
while (num1 >= 0x80)
{
data[i] = (unsigned char)(num1 | 0x80); i++;
num1 = num1 >> 7;
}
data[i]=num1;
data.resize(i+1);
data+=str.toUtf8();
return data;
}
QString dataToString(QByteArray data)
{
// Variable UInt32
unsigned char num3;
int num = 0;
int num2 = 0;
int i=0;
do
{
num3 = data[i]; i++;
num |= (num3 & 0x7f) << num2;
num2 += 7;
} while ((num3 & 0x80) != 0);
unsigned int strlen = (uint) num;
if (!strlen)
return QString();
data = data.right(data.size()-i); // Remove the strlen
data.truncate(strlen);
return QString(data);
}
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
{
uint endvalue=0;
uint value=0;
if (numberOfBits <= 8)
{
endvalue = (uchar)data[0];
goto done;
}
value = (uchar)data[0];
numberOfBits -= 8;
if (numberOfBits <= 8)
{
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
goto done;
}
value |= (uint) (((uchar)data[1]) << 8);
numberOfBits -= 8;
if (numberOfBits <= 8)
{
uint num2 = (uint) (((uchar)data[2]) << 0x10);
endvalue = (value | num2);
goto done;
}
value |= (uint) (((uchar)data[2]) << 0x10);
numberOfBits -= 8;
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
goto done;
done:
float num = max - min;
int num2 = (((int) 1) << numberOfBits) - 1;
float num3 = endvalue;
float num4 = num3 / ((float) num2);
return (min + (num4 * num));
}
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
{
QByteArray data;
float num = max - min;
float num2 = (value - min) / num;
int num3 = (((int) 1) << numberOfBits) - 1;
uint source = num3 * num2;
if (numberOfBits <= 8)
{
data += (unsigned char)source;
return data;
}
data += (unsigned char)source;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>8;
return data;
}
data += (unsigned char)source>>8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>16;
return data;
}
data += (unsigned char)source>>16;
data += (unsigned char)source>>24;
return data;
}
uint8_t dataToUint8(QByteArray data)
{
return (uint8_t)data[0];
}
uint16_t dataToUint16(QByteArray data)
{
return ((uint16_t)(uint8_t)data[0])
+(((uint16_t)(uint8_t)data[1])<<8);
}
uint32_t dataToUint32(QByteArray data)
{
return ((uint32_t)(uint8_t)data[0])
+(((uint32_t)(uint8_t)data[1])<<8)
+(((uint32_t)(uint8_t)data[2])<<16)
+(((uint32_t)(uint8_t)data[3])<<24);
}
uint64_t dataToUint64(QByteArray data)
{
return ((uint64_t)(uint8_t)data[0])
+(((uint64_t)(uint8_t)data[1])<<8)
+(((uint64_t)(uint8_t)data[2])<<16)
+(((uint64_t)(uint8_t)data[3])<<24)
+(((uint64_t)(uint8_t)data[4])<<32)
+(((uint64_t)(uint8_t)data[5])<<40)
+(((uint64_t)(uint8_t)data[6])<<48)
+(((uint64_t)(uint8_t)data[7])<<56);
}
unsigned getVUint32Size(QByteArray data)
{
unsigned lensize=0;
{
unsigned char num3;
do {
num3 = data[lensize];
lensize++;
} while ((num3 & 0x80) != 0);
}
return lensize;
}
QByteArray uint8ToData(uint8_t num)
{
QByteArray data(1,0);
data[0] = (uint8_t)num;
return data;
}
QByteArray uint16ToData(uint16_t num)
{
QByteArray data(2,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
return data;
}
QByteArray uint32ToData(uint32_t num)
{
QByteArray data(4,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
return data;
}
QByteArray uint64ToData(uint64_t num)
{
QByteArray data(8,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
data[4] = (uint8_t)((num>>32) & 0xFF);
data[5] = (uint8_t)((num>>40) & 0xFF);
data[6] = (uint8_t)((num>>48) & 0xFF);
data[7] = (uint8_t)((num>>56) & 0xFF);
return data;
}

45
src/misc/serialize.h Normal file
View File

@ -0,0 +1,45 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <cstdint>
#include <QByteArray>
#include <QString>
/// Most of those functions are unsafe unless otherwise specified
/// Do not use them on untrusted data (e.g. check a signature first)
QByteArray doubleToData(double num);
QByteArray floatToData(float num);
float dataToFloat(QByteArray data);
QByteArray stringToData(QString str);
QString dataToString(QByteArray data);
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
uint8_t dataToUint8(QByteArray data);
uint16_t dataToUint16(QByteArray data);
uint32_t dataToUint32(QByteArray data);
uint64_t dataToUint64(QByteArray data);
unsigned getVUint32Size(QByteArray data);
QByteArray uint8ToData(uint8_t num);
QByteArray uint16ToData(uint16_t num);
QByteArray uint32ToData(uint32_t num);
QByteArray uint64ToData(uint64_t num);
#endif // SERIALIZE_H

View File

@ -119,6 +119,7 @@ void Settings::load()
proxyPort = s.value("proxyPort", 0).toInt(); proxyPort = s.value("proxyPort", 0).toInt();
currentProfile = s.value("currentProfile", "").toString(); currentProfile = s.value("currentProfile", "").toString();
autoAwayTime = s.value("autoAwayTime", 10).toInt(); autoAwayTime = s.value("autoAwayTime", 10).toInt();
checkUpdates = s.value("checkUpdates", false).toBool();
s.endGroup(); s.endGroup();
s.beginGroup("Widgets"); s.beginGroup("Widgets");
@ -255,6 +256,7 @@ void Settings::save(QString path)
s.setValue("proxyPort", proxyPort); s.setValue("proxyPort", proxyPort);
s.setValue("currentProfile", currentProfile); s.setValue("currentProfile", currentProfile);
s.setValue("autoAwayTime", autoAwayTime); s.setValue("autoAwayTime", autoAwayTime);
s.setValue("checkUpdates", checkUpdates);
s.endGroup(); s.endGroup();
s.beginGroup("Widgets"); s.beginGroup("Widgets");
@ -727,6 +729,16 @@ void Settings::setWindowState(const QByteArray &value)
windowState = value; windowState = value;
} }
bool Settings::getCheckUpdates() const
{
return checkUpdates;
}
void Settings::setCheckUpdates(bool newValue)
{
checkUpdates = newValue;
}
QByteArray Settings::getSplitterState() const QByteArray Settings::getSplitterState() const
{ {
return splitterState; return splitterState;

View File

@ -99,6 +99,9 @@ public:
int getAutoAwayTime() const; int getAutoAwayTime() const;
void setAutoAwayTime(int newValue); void setAutoAwayTime(int newValue);
bool getCheckUpdates() const;
void setCheckUpdates(bool newValue);
QPixmap getSavedAvatar(const QString& ownerId); QPixmap getSavedAvatar(const QString& ownerId);
void saveAvatar(QPixmap& pic, const QString& ownerId); void saveAvatar(QPixmap& pic, const QString& ownerId);
@ -219,6 +222,7 @@ private:
bool closeToTray; bool closeToTray;
bool minimizeToTray; bool minimizeToTray;
bool useEmoticons; bool useEmoticons;
bool checkUpdates;
bool forceTCP; bool forceTCP;

View File

@ -27,6 +27,8 @@
#include <QFileDialog> #include <QFileDialog>
#include <QStandardPaths> #include <QStandardPaths>
#include "src/autoupdate.h"
static QStringList locales = {"bg", "de", "en", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"}; static QStringList locales = {"bg", "de", "en", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"};
static QStringList langs = {"Български", "Deustch", "English", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "Suomi", "Svenska", "Українська"}; static QStringList langs = {"Български", "Deustch", "English", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "Suomi", "Svenska", "Українська"};
@ -40,6 +42,9 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
bodyUI = new Ui::GeneralSettings; bodyUI = new Ui::GeneralSettings;
bodyUI->setupUi(this); bodyUI->setupUi(this);
bodyUI->checkUpdates->setVisible(AUTOUPDATE_ENABLED);
bodyUI->checkUpdates->setChecked(Settings::getInstance().getCheckUpdates());
bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6()); bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6());
for (int i = 0; i < langs.size(); i++) for (int i = 0; i < langs.size(); i++)
bodyUI->transComboBox->insertItem(i, langs[i]); bodyUI->transComboBox->insertItem(i, langs[i]);
@ -93,6 +98,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
onUseProxyUpdated(); onUseProxyUpdated();
//general //general
connect(bodyUI->checkUpdates, &QCheckBox::stateChanged, this, &GeneralForm::onCheckUpdateChanged);
connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated())); connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated()));
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated); connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated);
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray); connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
@ -280,3 +286,8 @@ void GeneralForm::reloadSmiles()
bodyUI->smile4->setToolTip(smiles[3]); bodyUI->smile4->setToolTip(smiles[3]);
bodyUI->smile5->setToolTip(smiles[4]); bodyUI->smile5->setToolTip(smiles[4]);
} }
void GeneralForm::onCheckUpdateChanged()
{
Settings::getInstance().setCheckUpdates(bodyUI->checkUpdates->isChecked());
}

View File

@ -51,6 +51,7 @@ private slots:
void onReconnectClicked(); void onReconnectClicked();
void onAutoAcceptFileChange(); void onAutoAcceptFileChange();
void onAutoSaveDirChange(); void onAutoSaveDirChange();
void onCheckUpdateChanged();
private: private:
Ui::GeneralSettings *bodyUI; Ui::GeneralSettings *bodyUI;

View File

@ -40,7 +40,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>511</width> <width>511</width>
<height>739</height> <height>720</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1"> <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
@ -121,6 +121,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="checkUpdates">
<property name="text">
<string>Check for updates on startup (unstable)</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item alignment="Qt::AlignLeft"> <item alignment="Qt::AlignLeft">

View File

@ -31,6 +31,9 @@
#include "src/video/camera.h" #include "src/video/camera.h"
#include "form/chatform.h" #include "form/chatform.h"
#include "maskablepixmapwidget.h" #include "maskablepixmapwidget.h"
#include "src/historykeeper.h"
#include "form/inputpassworddialog.h"
#include "src/autoupdate.h"
#include <QMessageBox> #include <QMessageBox>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
@ -45,9 +48,7 @@
#include <QTimer> #include <QTimer>
#include <QStyleFactory> #include <QStyleFactory>
#include <QTranslator> #include <QTranslator>
#include "src/historykeeper.h"
#include <tox/tox.h> #include <tox/tox.h>
#include "form/inputpassworddialog.h"
Widget *Widget::instance{nullptr}; Widget *Widget::instance{nullptr};
@ -244,6 +245,11 @@ void Widget::init()
coreThread->start(); coreThread->start();
addFriendForm->show(*ui); addFriendForm->show(*ui);
#if (AUTOUPDATE_ENABLED)
if (Settings::getInstance().getCheckUpdates())
AutoUpdater::checkUpdatesAsyncInteractive();
#endif
} }
void Widget::setTranslation() void Widget::setTranslation()
@ -1095,3 +1101,20 @@ void Widget::setEnabledThreadsafe(bool enabled)
return setEnabled(enabled); return setEnabled(enabled);
} }
} }
bool Widget::askMsgboxQuestion(const QString& title, const QString& msg)
{
// We can only display widgets from the GUI thread
if (QThread::currentThread() != qApp->thread())
{
bool ret;
QMetaObject::invokeMethod(this, "askMsgboxQuestion", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
return ret;
}
else
{
return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes;
}
}

View File

@ -67,6 +67,7 @@ public:
Q_INVOKABLE QMessageBox::StandardButton showWarningMsgBox(const QString& title, const QString& msg, Q_INVOKABLE QMessageBox::StandardButton showWarningMsgBox(const QString& title, const QString& msg,
QMessageBox::StandardButtons buttonss = QMessageBox::Ok); QMessageBox::StandardButtons buttonss = QMessageBox::Ok);
Q_INVOKABLE void setEnabledThreadsafe(bool enabled); Q_INVOKABLE void setEnabledThreadsafe(bool enabled);
Q_INVOKABLE bool askMsgboxQuestion(const QString& title, const QString& msg);
~Widget(); ~Widget();
virtual void closeEvent(QCloseEvent *event); virtual void closeEvent(QCloseEvent *event);

View File

@ -0,0 +1,97 @@
#include <iostream>
#include <QFile>
#include <QByteArray>
#include <QDir>
#include <QCryptographicHash>
#include <sodium.h>
#include "serialize.h"
using namespace std;
/// Pass the target folder as first argument, no spaces allowed. We'll call that dir $TARGET
/// Update the content of $TARGET/files/ before calling this tool
/// We'll generate $TARGET/flist and exit
/// We need qtox-updater-skey in our working directory to sign the flist
///
/// The generated flist is very simple and just installs everything in the working directory ...
int main(int argc, char* argv[])
{
cout << "qTox updater flist generator" << endl;
/// First some basic error handling, prepare our handles, ...
if (argc != 2)
{
cout << "ERROR: qtox-updater-genflist takes the target path in argument" << endl;
return 1;
}
QFile skeyFile("qtox-updater-skey");
if (!skeyFile.open(QIODevice::ReadOnly))
{
cout << "ERROR: qtox-updater-genflist can't open the secret (private) key file" << endl;
return 1;
}
QByteArray skeyData = skeyFile.readAll();
skeyData = QByteArray::fromHex(skeyData);
skeyFile.close();
QString target(argv[1]);
QFile flistFile(target+"/flist");
if (!flistFile.open(QIODevice::Truncate | QIODevice::WriteOnly))
{
cout << "ERROR: qtox-updater-genflist can't open the target flist" << endl;
return 1;
}
QDir fdir(target+"/files/");
if (!fdir.isReadable())
{
cout << "ERROR: qtox-updater-genflist can't open the target files directory" << endl;
return 1;
}
QStringList filesListStr = fdir.entryList(QDir::Files);
/// Serialize the flist data
QByteArray flistData;
for (QString fileStr : filesListStr)
{
cout << "Adding "<<fileStr.toStdString()<<"..."<<endl;
QFile file(target+"/files/"+fileStr);
if (!file.open(QIODevice::ReadOnly))
{
cout << "ERROR: qtox-updater-genflist couldn't open a target file to sign it" << endl;
return 1;
}
QByteArray fileData = file.readAll();
unsigned char sig[crypto_sign_BYTES];
crypto_sign_detached(sig, nullptr, (unsigned char*)fileData.data(), fileData.size(), (unsigned char*)skeyData.data());
flistData += QByteArray::fromRawData((char*)sig, crypto_sign_BYTES);
flistData += stringToData(QCryptographicHash::hash(fileStr.toUtf8(), QCryptographicHash::Sha3_224).toHex());
flistData += stringToData("./"+fileStr); ///< Always install in the working directory for now
flistData += uint64ToData(fileData.size());
file.close();
}
cout << "Signing and writing the flist..."<<endl;
/// Sign our flist
unsigned char sig[crypto_sign_BYTES];
crypto_sign_detached(sig, nullptr, (unsigned char*)flistData.data(), flistData.size(), (unsigned char*)skeyData.data());
/// Write the flist
flistFile.write("1");
flistFile.write((char*)sig, crypto_sign_BYTES);
flistFile.write(flistData);
flistFile.close();
return 0;
}

View File

@ -0,0 +1,10 @@
TEMPLATE = app
CONFIG += console c++11
QT += core
LIBS += -lsodium
SOURCES += main.cpp \
serialize.cpp
HEADERS += \
serialize.h

View File

@ -0,0 +1,254 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "serialize.h"
QByteArray doubleToData(double num)
{
union
{
char tab[8];
double n;
} castUnion;
//char n[8];
//*((double*) n) = num;
castUnion.n=num;
return QByteArray(castUnion.tab,8);
}
QByteArray floatToData(float num)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.n=num;
return QByteArray(castUnion.tab,4);
}
float dataToFloat(QByteArray data)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.tab[0]=data.data()[0];
castUnion.tab[1]=data.data()[1];
castUnion.tab[2]=data.data()[2];
castUnion.tab[3]=data.data()[3];
return castUnion.n;
}
// Converts a string into PNet string data
QByteArray stringToData(QString str)
{
QByteArray data(4,0);
// Write the size in a Uint of variable lenght (8-32 bits)
int i=0;
uint num1 = (uint)str.toUtf8().size();
while (num1 >= 0x80)
{
data[i] = (unsigned char)(num1 | 0x80); i++;
num1 = num1 >> 7;
}
data[i]=num1;
data.resize(i+1);
data+=str.toUtf8();
return data;
}
QString dataToString(QByteArray data)
{
// Variable UInt32
unsigned char num3;
int num = 0;
int num2 = 0;
int i=0;
do
{
num3 = data[i]; i++;
num |= (num3 & 0x7f) << num2;
num2 += 7;
} while ((num3 & 0x80) != 0);
unsigned int strlen = (uint) num;
if (!strlen)
return QString();
data = data.right(data.size()-i); // Remove the strlen
data.truncate(strlen);
return QString(data);
}
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
{
uint endvalue=0;
uint value=0;
if (numberOfBits <= 8)
{
endvalue = (uchar)data[0];
goto done;
}
value = (uchar)data[0];
numberOfBits -= 8;
if (numberOfBits <= 8)
{
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
goto done;
}
value |= (uint) (((uchar)data[1]) << 8);
numberOfBits -= 8;
if (numberOfBits <= 8)
{
uint num2 = (uint) (((uchar)data[2]) << 0x10);
endvalue = (value | num2);
goto done;
}
value |= (uint) (((uchar)data[2]) << 0x10);
numberOfBits -= 8;
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
goto done;
done:
float num = max - min;
int num2 = (((int) 1) << numberOfBits) - 1;
float num3 = endvalue;
float num4 = num3 / ((float) num2);
return (min + (num4 * num));
}
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
{
QByteArray data;
float num = max - min;
float num2 = (value - min) / num;
int num3 = (((int) 1) << numberOfBits) - 1;
uint source = num3 * num2;
if (numberOfBits <= 8)
{
data += (unsigned char)source;
return data;
}
data += (unsigned char)source;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>8;
return data;
}
data += (unsigned char)source>>8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>16;
return data;
}
data += (unsigned char)source>>16;
data += (unsigned char)source>>24;
return data;
}
uint8_t dataToUint8(QByteArray data)
{
return (uint8_t)data[0];
}
uint16_t dataToUint16(QByteArray data)
{
return ((uint16_t)(uint8_t)data[0])
+(((uint16_t)(uint8_t)data[1])<<8);
}
uint32_t dataToUint32(QByteArray data)
{
return ((uint32_t)(uint8_t)data[0])
+(((uint32_t)(uint8_t)data[1])<<8)
+(((uint32_t)(uint8_t)data[2])<<16)
+(((uint32_t)(uint8_t)data[3])<<24);
}
uint64_t dataToUint64(QByteArray data)
{
return ((uint64_t)(uint8_t)data[0])
+(((uint64_t)(uint8_t)data[1])<<8)
+(((uint64_t)(uint8_t)data[2])<<16)
+(((uint64_t)(uint8_t)data[3])<<24)
+(((uint64_t)(uint8_t)data[4])<<32)
+(((uint64_t)(uint8_t)data[5])<<40)
+(((uint64_t)(uint8_t)data[6])<<48)
+(((uint64_t)(uint8_t)data[7])<<56);
}
unsigned getVUint32Size(QByteArray data)
{
unsigned lensize=0;
{
unsigned char num3;
do {
num3 = data[lensize];
lensize++;
} while ((num3 & 0x80) != 0);
}
return lensize;
}
QByteArray uint8ToData(uint8_t num)
{
QByteArray data(1,0);
data[0] = (uint8_t)num;
return data;
}
QByteArray uint16ToData(uint16_t num)
{
QByteArray data(2,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
return data;
}
QByteArray uint32ToData(uint32_t num)
{
QByteArray data(4,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
return data;
}
QByteArray uint64ToData(uint64_t num)
{
QByteArray data(8,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
data[4] = (uint8_t)((num>>32) & 0xFF);
data[5] = (uint8_t)((num>>40) & 0xFF);
data[6] = (uint8_t)((num>>48) & 0xFF);
data[7] = (uint8_t)((num>>56) & 0xFF);
return data;
}

View File

@ -0,0 +1,45 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <cstdint>
#include <QByteArray>
#include <QString>
/// Most of those functions are unsafe unless otherwise specified
/// Do not use them on untrusted data (e.g. check a signature first)
QByteArray doubleToData(double num);
QByteArray floatToData(float num);
float dataToFloat(QByteArray data);
QByteArray stringToData(QString str);
QString dataToString(QByteArray data);
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
uint8_t dataToUint8(QByteArray data);
uint16_t dataToUint16(QByteArray data);
uint32_t dataToUint32(QByteArray data);
uint64_t dataToUint64(QByteArray data);
unsigned getVUint32Size(QByteArray data);
QByteArray uint8ToData(uint8_t num);
QByteArray uint16ToData(uint16_t num);
QByteArray uint32ToData(uint32_t num);
QByteArray uint64ToData(uint64_t num);
#endif // SERIALIZE_H

View File

@ -0,0 +1,43 @@
#include <sodium.h>
#include <QByteArray>
#include <QFile>
using namespace std;
int main(int argc, char* argv[])
{
QFile io;
QByteArray msg;
if (argc > 1)
{
msg = QByteArray(argv[1]);
}
else
{
io.open(stdin, QIODevice::ReadOnly);
msg = io.readAll();
io.close();
}
io.open(stdout, QIODevice::WriteOnly);
QFile skeyFile("qtox-updater-skey");
if (!skeyFile.open(QIODevice::ReadOnly))
{
io.write("ERROR: qtox-updater-sign can't open the secret (private) key file\n");
io.close();
return 1;
}
QByteArray skeyData = skeyFile.readAll();
skeyData = QByteArray::fromHex(skeyData);
skeyFile.close();
unsigned char sig[crypto_sign_BYTES];
crypto_sign_detached(sig, nullptr, (unsigned char*)msg.data(), msg.size(), (unsigned char*)skeyData.data());
io.write((char*)sig, crypto_sign_BYTES);
io.write(msg);
io.close();
return 0;
}

View File

@ -0,0 +1,7 @@
TEMPLATE = app
CONFIG += console c++11
QT += core
SOURCES += main.cpp
LIBS += -lsodium

28
updater/main.cpp Normal file
View File

@ -0,0 +1,28 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

5
updater/res.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>res/qtox-256x256.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

254
updater/serialize.cpp Normal file
View File

@ -0,0 +1,254 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "serialize.h"
QByteArray doubleToData(double num)
{
union
{
char tab[8];
double n;
} castUnion;
//char n[8];
//*((double*) n) = num;
castUnion.n=num;
return QByteArray(castUnion.tab,8);
}
QByteArray floatToData(float num)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.n=num;
return QByteArray(castUnion.tab,4);
}
float dataToFloat(QByteArray data)
{
union
{
char tab[4];
float n;
} castUnion;
castUnion.tab[0]=data.data()[0];
castUnion.tab[1]=data.data()[1];
castUnion.tab[2]=data.data()[2];
castUnion.tab[3]=data.data()[3];
return castUnion.n;
}
// Converts a string into PNet string data
QByteArray stringToData(QString str)
{
QByteArray data(4,0);
// Write the size in a Uint of variable lenght (8-32 bits)
int i=0;
uint num1 = (uint)str.toUtf8().size();
while (num1 >= 0x80)
{
data[i] = (unsigned char)(num1 | 0x80); i++;
num1 = num1 >> 7;
}
data[i]=num1;
data.resize(i+1);
data+=str.toUtf8();
return data;
}
QString dataToString(QByteArray data)
{
// Variable UInt32
unsigned char num3;
int num = 0;
int num2 = 0;
int i=0;
do
{
num3 = data[i]; i++;
num |= (num3 & 0x7f) << num2;
num2 += 7;
} while ((num3 & 0x80) != 0);
unsigned int strlen = (uint) num;
if (!strlen)
return QString();
data = data.right(data.size()-i); // Remove the strlen
data.truncate(strlen);
return QString(data);
}
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
{
uint endvalue=0;
uint value=0;
if (numberOfBits <= 8)
{
endvalue = (uchar)data[0];
goto done;
}
value = (uchar)data[0];
numberOfBits -= 8;
if (numberOfBits <= 8)
{
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
goto done;
}
value |= (uint) (((uchar)data[1]) << 8);
numberOfBits -= 8;
if (numberOfBits <= 8)
{
uint num2 = (uint) (((uchar)data[2]) << 0x10);
endvalue = (value | num2);
goto done;
}
value |= (uint) (((uchar)data[2]) << 0x10);
numberOfBits -= 8;
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
goto done;
done:
float num = max - min;
int num2 = (((int) 1) << numberOfBits) - 1;
float num3 = endvalue;
float num4 = num3 / ((float) num2);
return (min + (num4 * num));
}
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
{
QByteArray data;
float num = max - min;
float num2 = (value - min) / num;
int num3 = (((int) 1) << numberOfBits) - 1;
uint source = num3 * num2;
if (numberOfBits <= 8)
{
data += (unsigned char)source;
return data;
}
data += (unsigned char)source;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>8;
return data;
}
data += (unsigned char)source>>8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
data += (unsigned char)source>>16;
return data;
}
data += (unsigned char)source>>16;
data += (unsigned char)source>>24;
return data;
}
uint8_t dataToUint8(QByteArray data)
{
return (uint8_t)data[0];
}
uint16_t dataToUint16(QByteArray data)
{
return ((uint16_t)(uint8_t)data[0])
+(((uint16_t)(uint8_t)data[1])<<8);
}
uint32_t dataToUint32(QByteArray data)
{
return ((uint32_t)(uint8_t)data[0])
+(((uint32_t)(uint8_t)data[1])<<8)
+(((uint32_t)(uint8_t)data[2])<<16)
+(((uint32_t)(uint8_t)data[3])<<24);
}
uint64_t dataToUint64(QByteArray data)
{
return ((uint64_t)(uint8_t)data[0])
+(((uint64_t)(uint8_t)data[1])<<8)
+(((uint64_t)(uint8_t)data[2])<<16)
+(((uint64_t)(uint8_t)data[3])<<24)
+(((uint64_t)(uint8_t)data[4])<<32)
+(((uint64_t)(uint8_t)data[5])<<40)
+(((uint64_t)(uint8_t)data[6])<<48)
+(((uint64_t)(uint8_t)data[7])<<56);
}
unsigned getVUint32Size(QByteArray data)
{
unsigned lensize=0;
{
unsigned char num3;
do {
num3 = data[lensize];
lensize++;
} while ((num3 & 0x80) != 0);
}
return lensize;
}
QByteArray uint8ToData(uint8_t num)
{
QByteArray data(1,0);
data[0] = (uint8_t)num;
return data;
}
QByteArray uint16ToData(uint16_t num)
{
QByteArray data(2,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
return data;
}
QByteArray uint32ToData(uint32_t num)
{
QByteArray data(4,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
return data;
}
QByteArray uint64ToData(uint64_t num)
{
QByteArray data(8,0);
data[0] = (uint8_t)(num & 0xFF);
data[1] = (uint8_t)((num>>8) & 0xFF);
data[2] = (uint8_t)((num>>16) & 0xFF);
data[3] = (uint8_t)((num>>24) & 0xFF);
data[4] = (uint8_t)((num>>32) & 0xFF);
data[5] = (uint8_t)((num>>40) & 0xFF);
data[6] = (uint8_t)((num>>48) & 0xFF);
data[7] = (uint8_t)((num>>56) & 0xFF);
return data;
}

45
updater/serialize.h Normal file
View File

@ -0,0 +1,45 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <cstdint>
#include <QByteArray>
#include <QString>
/// Most of those functions are unsafe unless otherwise specified
/// Do not use them on untrusted data (e.g. check a signature first)
QByteArray doubleToData(double num);
QByteArray floatToData(float num);
float dataToFloat(QByteArray data);
QByteArray stringToData(QString str);
QString dataToString(QByteArray data);
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
uint8_t dataToUint8(QByteArray data);
uint16_t dataToUint16(QByteArray data);
uint32_t dataToUint32(QByteArray data);
uint64_t dataToUint64(QByteArray data);
unsigned getVUint32Size(QByteArray data);
QByteArray uint8ToData(uint8_t num);
QByteArray uint16ToData(uint16_t num);
QByteArray uint32ToData(uint32_t num);
QByteArray uint64ToData(uint64_t num);
#endif // SERIALIZE_H

52
updater/settingsDir.cpp Normal file
View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "settingsDir.h"
#include <QFile>
#include <QSettings>
#include <QDir>
#include <QStandardPaths>
const QString FILENAME = "settings.ini";
QString getSettingsDirPath()
{
if (isToxPortableEnabled())
return ".";
#ifdef Q_OS_WIN
return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QDir::separator() + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox");
#else
return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox");
#endif
}
bool isToxPortableEnabled()
{
QFile portableSettings(FILENAME);
if (portableSettings.exists())
{
QSettings ps(FILENAME, QSettings::IniFormat);
ps.beginGroup("General");
return ps.value("makeToxPortable", false).toBool();
}
else
{
return false;
}
}

27
updater/settingsDir.h Normal file
View File

@ -0,0 +1,27 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef SETTINGSDIR_H
#define SETTINGSDIR_H
#include <QString>
QString getSettingsDirPath();
bool isToxPortableEnabled();
#endif // SETTINGSDIR_H

115
updater/update.cpp Normal file
View File

@ -0,0 +1,115 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "update.h"
#include "serialize.h"
#include <QFile>
#include <QDebug>
unsigned char key[crypto_sign_PUBLICKEYBYTES] =
{
0xa5, 0x80, 0xf3, 0xb7, 0xd0, 0x10, 0xc0, 0xf9, 0xd6, 0xcf, 0x48, 0x15, 0x99, 0x70, 0x92, 0x49,
0xf6, 0xe8, 0xe5, 0xe2, 0x6c, 0x73, 0x8c, 0x48, 0x25, 0xed, 0x01, 0x72, 0xf7, 0x6c, 0x17, 0x28
};
QByteArray getLocalFlist()
{
QByteArray flist;
QFile flistFile("flist");
if (!flistFile.open(QIODevice::ReadOnly))
{
qWarning() << "getLocalFlist: Can't open local flist";
return flist;
}
flist = flistFile.readAll();
flistFile.close();
return flist;
}
QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist)
{
QList<UpdateFileMeta> diff;
QList<UpdateFileMeta> localFlist = parseFlist(getLocalFlist());
for (UpdateFileMeta file : updateFlist)
if (!localFlist.contains(file))
diff += file;
return diff;
}
QList<UpdateFileMeta> parseFlist(QByteArray flistData)
{
QList<UpdateFileMeta> flist;
if (flistData.isEmpty())
{
qWarning() << "AutoUpdater::parseflist: Empty data";
return flist;
}
// Check version
if (flistData[0] != '1')
{
qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0];
return flist;
}
flistData = flistData.mid(1);
// Check signature
if (flistData.size() < (int)(crypto_sign_BYTES))
{
qWarning() << "AutoUpdater::parseflist: Truncated data";
return flist;
}
else
{
QByteArray msgData = flistData.mid(crypto_sign_BYTES);
unsigned char* msg = (unsigned char*)msgData.data();
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0)
{
qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE";
return flist;
}
flistData = flistData.mid(crypto_sign_BYTES);
}
// Parse. We assume no errors handling needed since the signature is valid.
while (!flistData.isEmpty())
{
UpdateFileMeta newFile;
memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES);
flistData = flistData.mid(crypto_sign_BYTES);
newFile.id = dataToString(flistData);
flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData));
newFile.installpath = dataToString(flistData);
flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData));
newFile.size = dataToUint64(flistData);
flistData = flistData.mid(8);
flist += newFile;
}
return flist;
}

55
updater/update.h Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef UPDATE_H
#define UPDATE_H
#include <QByteArray>
#include <QString>
#include <sodium.h>
struct UpdateFileMeta
{
unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519)
QString id; ///< Unique id of the file
QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute
uint64_t size; ///< Size in bytes of the file
bool operator==(const UpdateFileMeta& other)
{
return (size == other.size
&& id == other.id && installpath == other.installpath
&& memcmp(sig, other.sig, crypto_sign_BYTES) == 0);
}
};
struct UpdateFile
{
UpdateFileMeta metadata;
QByteArray data;
};
/// Gets the local flist. Returns an empty array on error
QByteArray getLocalFlist();
/// Parses and validates a flist file. Returns an empty list on error
QList<UpdateFileMeta> parseFlist(QByteArray flistData);
/// Generates a list of files we need to update
QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist);
extern unsigned char key[crypto_sign_PUBLICKEYBYTES];
#endif // UPDATE_H

36
updater/updater.pro Normal file
View File

@ -0,0 +1,36 @@
#-------------------------------------------------
#
# Project created by QtCreator 2014-11-09T21:09:08
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtox-updater
TEMPLATE = app
CONFIG += c++11
SOURCES += main.cpp\
widget.cpp \
settingsDir.cpp \
update.cpp \
serialize.cpp
HEADERS += widget.h \
settingsDir.h \
update.h \
serialize.h
FORMS += widget.ui
RESOURCES += \
res.qrc
INCLUDEPATH += libs/include
RC_FILE = windows/updater.rc
LIBS += -L$$PWD/libs/lib/ -lsodium

156
updater/widget.cpp Normal file
View File

@ -0,0 +1,156 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#include "widget.h"
#include "ui_widget.h"
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QMessageBox>
#include <QMetaObject>
#include "settingsDir.h"
#include "update.h"
#ifdef Q_OS_WIN
const bool supported = true;
const QString QTOX_PATH = "qtox.exe";
#else
const bool supported = false;
const QString QTOX_PATH;
#endif
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// Updates only for supported platforms
if (!supported)
{
fatalError(tr("The qTox updater is not supported on this platform."));
}
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
}
Widget::~Widget()
{
delete ui;
}
void Widget::setProgress(int value)
{
ui->progress->setValue(value);
qApp->processEvents();
}
void Widget::fatalError(QString message)
{
QMessageBox::critical(this,tr("Error"), message+'\n'+tr("qTox will restart now."));
deleteUpdate();
startQToxAndExit();
}
void Widget::deleteUpdate()
{
QDir updateDir(getSettingsDirPath()+"/update/");
updateDir.removeRecursively();
}
void Widget::startQToxAndExit()
{
QProcess::startDetached(QTOX_PATH);
exit(0);
}
void Widget::update()
{
/// 1. Find and parse the update (0-5%)
// Check that the dir exists
QString updateDirStr = getSettingsDirPath()+"/update/";
QDir updateDir(updateDirStr);
if (!updateDir.exists())
fatalError(tr("No update found."));
// Check that we have a flist and that every file on the diff exists
QFile updateFlistFile(updateDirStr+"flist");
if (!updateFlistFile.open(QIODevice::ReadOnly))
fatalError(tr("The update is incomplete."));
QByteArray updateFlistData = updateFlistFile.readAll();
updateFlistFile.close();
setProgress(1);
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
setProgress(2);
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
setProgress(4);
for (UpdateFileMeta fileMeta : diff)
if (!QFile::exists(updateDirStr+fileMeta.installpath))
fatalError(tr("The update is incomplete."));
setProgress(5);
/// 2. Check the update (5-50%)
float checkProgressStep = 45/diff.size();
float checkProgress = 5;
for (UpdateFileMeta fileMeta : diff)
{
UpdateFile file;
file.metadata = fileMeta;
QFile fileFile(updateDirStr+fileMeta.installpath);
if (!fileFile.open(QIODevice::ReadOnly))
fatalError(tr("Update files are unreadable."));
file.data = fileFile.readAll();
fileFile.close();
if (file.data.size() != (int)fileMeta.size)
fatalError(tr("Update files are corrupted."));
if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(),
file.data.size(), key) != 0)
fatalError(tr("Update files are corrupted."));
checkProgress += checkProgressStep;
setProgress(checkProgress);
}
setProgress(50);
/// 3. Install the update (50-95%)
float installProgressStep = 45/diff.size();
float installProgress = 50;
for (UpdateFileMeta fileMeta : diff)
{
QFile fileFile(updateDirStr+fileMeta.installpath);
if (!fileFile.copy(fileMeta.installpath))
fatalError(tr("Unable to copy the update's files."));
installProgress += installProgressStep;
setProgress(installProgress);
}
setProgress(95);
/// 4. Delete the update (95-100%)
deleteUpdate();
setProgress(100);
/// 5. Start qTox and exit
startQToxAndExit();
}

51
updater/widget.h Normal file
View File

@ -0,0 +1,51 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
// Utilities
void setProgress(int value);
// Noreturn
void fatalError(QString message); ///< Calls deleteUpdate and startQToxAndExit
void deleteUpdate();
void startQToxAndExit();
public slots:
// Finds and applies the update
void update();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H

139
updater/widget.ui Normal file
View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>224</height>
</rect>
</property>
<property name="windowTitle">
<string>qTox Updater</string>
</property>
<property name="windowIcon">
<iconset resource="res.qrc">
<normaloff>:/res/qtox-256x256.png</normaloff>:/res/qtox-256x256.png</iconset>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>0</x>
<y>13</y>
<width>191</width>
<height>191</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="res.qrc">:/res/qtox-256x256.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
<widget class="QProgressBar" name="progress">
<property name="geometry">
<rect>
<x>206</x>
<y>95</y>
<width>171</width>
<height>20</height>
</rect>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>205</x>
<y>115</y>
<width>171</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Updating qTox ...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>201</x>
<y>170</y>
<width>181</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>&lt;a href=&quot;https://tox.im&quot;&gt;https://tox.im&lt;/a&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>200</x>
<y>183</y>
<width>181</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>&lt;a href=&quot;https://github.com/tux3/qtox&quot;&gt;https://github.com/tux3/qtox&lt;/a&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>195</x>
<y>32</y>
<width>191</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>qTox Update</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

BIN
updater/windows/updater.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,2 @@
ID_ICON ICON DISCARDABLE "updater.ico"
1 24 "updater.exe.manifest"